mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-13 03:34:35 +00:00
refactoring
This commit is contained in:
parent
bb90fdc5fc
commit
893df7272f
@ -26,34 +26,24 @@
|
|||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
SdOverUsbView::SdOverUsbView(NavigationView& nav) : nav_ (nav) {
|
SdOverUsbView::SdOverUsbView(NavigationView& nav) : nav_ (nav) {
|
||||||
|
|
||||||
sdcDisconnect(&SDCD1);
|
|
||||||
sdcStop(&SDCD1);
|
|
||||||
|
|
||||||
portapack::shutdown();
|
|
||||||
m4_init(portapack::spi_flash::image_tag_usb_sd, portapack::memory::map::m4_code, false);
|
|
||||||
//m4_init(portapack::spi_flash::image_tag_hackrf, portapack::memory::map::m4_code_hackrf, true);
|
|
||||||
m0_halt(); /* will not return*/
|
|
||||||
//baseband::run_image();
|
|
||||||
|
|
||||||
|
|
||||||
add_children({
|
add_children({
|
||||||
&labels,
|
&labels,
|
||||||
&button_close
|
&button_run
|
||||||
});
|
});
|
||||||
|
|
||||||
button_close.on_select = [this](Button&) {
|
button_run.on_select = [this](Button&) {
|
||||||
nav_.pop();
|
sdcDisconnect(&SDCD1);
|
||||||
|
sdcStop(&SDCD1);
|
||||||
|
|
||||||
|
portapack::shutdown(true);
|
||||||
|
m4_init(portapack::spi_flash::image_tag_usb_sd, portapack::memory::map::m4_code, false);
|
||||||
|
m0_halt();
|
||||||
|
/* will not return*/
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SdOverUsbView::~SdOverUsbView() {
|
|
||||||
baseband::shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdOverUsbView::focus() {
|
void SdOverUsbView::focus() {
|
||||||
button_close.focus();
|
button_run.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -37,7 +37,6 @@ namespace ui {
|
|||||||
class SdOverUsbView : public View {
|
class SdOverUsbView : public View {
|
||||||
public:
|
public:
|
||||||
SdOverUsbView(NavigationView& nav);
|
SdOverUsbView(NavigationView& nav);
|
||||||
~SdOverUsbView();
|
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
|
|
||||||
@ -47,15 +46,13 @@ private:
|
|||||||
NavigationView& nav_;
|
NavigationView& nav_;
|
||||||
|
|
||||||
Labels labels {
|
Labels labels {
|
||||||
{ { 4, 4 }, "Use USB", Color::white() }
|
{ { 40, 4 }, "This will provide access\nto the SD card over USB.", Color::white() }
|
||||||
};
|
};
|
||||||
|
|
||||||
Button button_close {
|
Button button_run {
|
||||||
{ 2 * 8, 15 * 16, 12 * 8, 3 * 16 },
|
{ 2 * 8, 15 * 16, 12 * 8, 3 * 16 },
|
||||||
"Close"
|
"Run"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -515,11 +515,13 @@ bool init() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown() {
|
void shutdown(const bool leave_screen_on) {
|
||||||
gpdma::controller.disable();
|
gpdma::controller.disable();
|
||||||
|
|
||||||
backlight()->off();
|
if (leave_screen_on) {
|
||||||
display.shutdown();
|
backlight()->off();
|
||||||
|
display.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
radio::disable();
|
radio::disable();
|
||||||
audio::shutdown();
|
audio::shutdown();
|
||||||
|
@ -63,7 +63,7 @@ void set_antenna_bias(const bool v);
|
|||||||
bool get_antenna_bias();
|
bool get_antenna_bias();
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
void shutdown();
|
void shutdown(const bool leave_screen_on = false);
|
||||||
|
|
||||||
Backlight* backlight();
|
Backlight* backlight();
|
||||||
|
|
||||||
|
@ -529,12 +529,12 @@ set(MODE_CPPSRC
|
|||||||
sd_over_usb/diskio.c
|
sd_over_usb/diskio.c
|
||||||
sd_over_usb/sd_over_usb.c
|
sd_over_usb/sd_over_usb.c
|
||||||
sd_over_usb/usb_descriptor.c
|
sd_over_usb/usb_descriptor.c
|
||||||
sd_over_usb/usb_device.c
|
|
||||||
sd_over_usb/usb_endpoint.c
|
|
||||||
sd_over_usb/usb.c
|
|
||||||
sd_over_usb/hackrf_core.c
|
sd_over_usb/hackrf_core.c
|
||||||
|
|
||||||
|
${HACKRF_PATH}/firmware/common/usb.c
|
||||||
${HACKRF_PATH}/firmware/common/usb_queue.c
|
${HACKRF_PATH}/firmware/common/usb_queue.c
|
||||||
|
${HACKRF_PATH}/firmware/hackrf_usb/usb_device.c
|
||||||
|
${HACKRF_PATH}/firmware/hackrf_usb/usb_endpoint.c
|
||||||
${HACKRF_PATH}/firmware/common/usb_request.c
|
${HACKRF_PATH}/firmware/common/usb_request.c
|
||||||
${HACKRF_PATH}/firmware/common/usb_standard_request.c
|
${HACKRF_PATH}/firmware/common/usb_standard_request.c
|
||||||
${HACKRF_PATH}/firmware/common/platform_detect.c
|
${HACKRF_PATH}/firmware/common/platform_detect.c
|
||||||
|
@ -24,13 +24,10 @@
|
|||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
|
|
||||||
#include "proc_sd_over_usb.hpp"
|
#include "proc_sd_over_usb.hpp"
|
||||||
|
|
||||||
#include "debug.hpp"
|
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void start_usb(void);
|
void start_usb(void);
|
||||||
void stop_usb(void);
|
|
||||||
void irq_usb(void);
|
void irq_usb(void);
|
||||||
void usb_transfer(void);
|
void usb_transfer(void);
|
||||||
|
|
||||||
@ -40,7 +37,6 @@ CH_IRQ_HANDLER(Vector60) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
sdcStart(&SDCD1, nullptr);
|
sdcStart(&SDCD1, nullptr);
|
||||||
if (sdcConnect(&SDCD1) == CH_FAILED) chDbgPanic("no sd card #1");
|
if (sdcConnect(&SDCD1) == CH_FAILED) chDbgPanic("no sd card #1");
|
||||||
|
|
||||||
@ -50,7 +46,5 @@ int main() {
|
|||||||
usb_transfer();
|
usb_transfer();
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_usb();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
#include "scsi.h"
|
#include "scsi.h"
|
||||||
#include "diskio.h"
|
#include "diskio.h"
|
||||||
|
|
||||||
#define HALT_UNTIL_DEBUGGING() \
|
|
||||||
while (!((*(volatile uint32_t *)0xE000EDF0) & (1 << 0))) {} \
|
|
||||||
__asm__ __volatile__("bkpt 1")
|
|
||||||
|
|
||||||
|
|
||||||
volatile bool usb_bulk_block_done = false;
|
volatile bool usb_bulk_block_done = false;
|
||||||
|
|
||||||
void usb_bulk_block_cb(void* user_data, unsigned int bytes_transferred) {
|
void usb_bulk_block_cb(void* user_data, unsigned int bytes_transferred) {
|
||||||
@ -104,8 +99,6 @@ uint8_t read_format_capacities(msd_cbw_t *msd_cbw_data) {
|
|||||||
.header = {0, 0, 0, 1 * 8 /* num_entries * 8 */},
|
.header = {0, 0, 0, 1 * 8 /* num_entries * 8 */},
|
||||||
.blocknum = {((num_blocks) >> 24)& 0xff, ((num_blocks) >> 16)& 0xff, ((num_blocks) >> 8)& 0xff, num_blocks & 0xff},
|
.blocknum = {((num_blocks) >> 24)& 0xff, ((num_blocks) >> 16)& 0xff, ((num_blocks) >> 8)& 0xff, num_blocks & 0xff},
|
||||||
.blocklen = {0b10 /* formated */, 0, (512) >> 8, 0},
|
.blocklen = {0b10 /* formated */, 0, (512) >> 8, 0},
|
||||||
// .blocknum2 = {((num_blocks) >> 24)& 0xff, ((num_blocks) >> 16)& 0xff, ((num_blocks) >> 8)& 0xff, num_blocks & 0xff},
|
|
||||||
// .blocklen2 = {0 /* formated */, 0, (512) >> 8, 0}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_read_format_capacities_response_t));
|
memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_read_format_capacities_response_t));
|
||||||
@ -155,7 +148,7 @@ uint8_t mode_sense6(msd_cbw_t *msd_cbw_data) {
|
|||||||
.byte = {
|
.byte = {
|
||||||
sizeof(scsi_mode_sense6_response_t) - 1,
|
sizeof(scsi_mode_sense6_response_t) - 1,
|
||||||
0,
|
0,
|
||||||
0, // 0x01 << 7, // 0 for not write protected
|
0,
|
||||||
0 }
|
0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -166,7 +159,6 @@ uint8_t mode_sense6(msd_cbw_t *msd_cbw_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static data_request_t decode_data_request(const uint8_t *cmd) {
|
static data_request_t decode_data_request(const uint8_t *cmd) {
|
||||||
|
|
||||||
data_request_t req;
|
data_request_t req;
|
||||||
uint32_t lba;
|
uint32_t lba;
|
||||||
uint16_t blk;
|
uint16_t blk;
|
||||||
@ -207,7 +199,6 @@ void scsi_command(msd_cbw_t *msd_cbw_data) {
|
|||||||
|
|
||||||
switch (msd_cbw_data->cmd_data[0]) {
|
switch (msd_cbw_data->cmd_data[0]) {
|
||||||
case SCSI_CMD_INQUIRY:
|
case SCSI_CMD_INQUIRY:
|
||||||
//status = handle_inquiry(msd_cbw_data);
|
|
||||||
if ((msd_cbw_data->cmd_data[1] & 0b1) && msd_cbw_data->cmd_data[2] == 0x80) {
|
if ((msd_cbw_data->cmd_data[1] & 0b1) && msd_cbw_data->cmd_data[2] == 0x80) {
|
||||||
status = handle_inquiry_serial_number(msd_cbw_data);
|
status = handle_inquiry_serial_number(msd_cbw_data);
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
#include <common/usb.h>
|
#include <common/usb.h>
|
||||||
#include <common/usb_request.h>
|
#include <common/usb_request.h>
|
||||||
#include <common/usb_standard_request.h>
|
#include <common/usb_standard_request.h>
|
||||||
#include "usb_device.h"
|
#include <hackrf_usb/usb_device.h>
|
||||||
#include "usb_endpoint.h"
|
#include <hackrf_usb/usb_endpoint.h>
|
||||||
#include <libopencm3/lpc43xx/m4/nvic.h>
|
#include <libopencm3/lpc43xx/m4/nvic.h>
|
||||||
#include <libopencm3/lpc43xx/cgu.h>
|
#include <libopencm3/lpc43xx/cgu.h>
|
||||||
#include "platform_detect.h"
|
#include "platform_detect.h"
|
||||||
@ -101,14 +101,6 @@ typedef struct {
|
|||||||
uint8_t blocklen[4];
|
uint8_t blocklen[4];
|
||||||
} scsi_read_format_capacities_response_t;
|
} scsi_read_format_capacities_response_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t header[4];
|
|
||||||
uint8_t blocknum[4];
|
|
||||||
uint8_t blocklen[4];
|
|
||||||
uint8_t blocknum2[4];
|
|
||||||
uint8_t blocklen2[4];
|
|
||||||
} scsi_read_format_capacities_double_response_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t last_block_addr;
|
uint32_t last_block_addr;
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
#include "sd_over_usb.h"
|
#include "sd_over_usb.h"
|
||||||
#include "scsi.h"
|
#include "scsi.h"
|
||||||
|
|
||||||
//extern usb_request_handlers_t usb_request_handlers;
|
|
||||||
#define HALT_UNTIL_DEBUGGING() \
|
|
||||||
while (!((*(volatile uint32_t *)0xE000EDF0) & (1 << 0))) {} \
|
|
||||||
__asm__ __volatile__("bkpt 1")
|
|
||||||
|
|
||||||
// uint8_t usb_buffer[USB_TRANSFER_SIZE];
|
|
||||||
|
|
||||||
|
|
||||||
bool scsi_running = false;
|
bool scsi_running = false;
|
||||||
|
|
||||||
usb_request_status_t report_max_lun(
|
usb_request_status_t report_max_lun(
|
||||||
@ -26,140 +18,33 @@ usb_request_status_t report_max_lun(
|
|||||||
|
|
||||||
usb_transfer_schedule_ack(endpoint->out);
|
usb_transfer_schedule_ack(endpoint->out);
|
||||||
|
|
||||||
/* start loop here?*/
|
|
||||||
scsi_running = true;
|
scsi_running = true;
|
||||||
// Host to Device. receive inquiry LUN
|
|
||||||
return USB_REQUEST_STATUS_OK;
|
|
||||||
}
|
}
|
||||||
else if (stage == USB_TRANSFER_STAGE_DATA) {
|
|
||||||
return USB_REQUEST_STATUS_OK;
|
|
||||||
}
|
|
||||||
else if (stage == USB_TRANSFER_STAGE_STATUS) {
|
|
||||||
// response here?
|
|
||||||
return USB_REQUEST_STATUS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
usb_request_status_t report_magic_scsi(
|
|
||||||
usb_endpoint_t* const endpoint,
|
|
||||||
const usb_transfer_stage_t stage)
|
|
||||||
{
|
|
||||||
|
|
||||||
// return USB_REQUEST_STATUS_OK;
|
|
||||||
|
|
||||||
|
|
||||||
// if (endpoint->address != 0x02) {
|
|
||||||
// HALT_UNTIL_DEBUGGING();
|
|
||||||
// return USB_REQUEST_STATUS_OK;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
|
||||||
return USB_REQUEST_STATUS_OK;
|
|
||||||
// usb_bulk_buffer[0] = 0x55;
|
|
||||||
// usb_bulk_buffer[1] = 0x55;
|
|
||||||
// usb_bulk_buffer[2] = 0x55;
|
|
||||||
// usb_bulk_buffer[3] = 0x55;
|
|
||||||
// usb_bulk_buffer[4] = 0;
|
|
||||||
|
|
||||||
// usb_transfer_schedule_block(
|
|
||||||
// &usb_endpoint_bulk_out,
|
|
||||||
// &usb_bulk_buffer[0x0000],
|
|
||||||
// 5,
|
|
||||||
// NULL,
|
|
||||||
// NULL);
|
|
||||||
|
|
||||||
// usb_transfer_schedule_ack(endpoint->out);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (stage == USB_TRANSFER_STAGE_DATA) {
|
|
||||||
HALT_UNTIL_DEBUGGING();
|
|
||||||
}
|
|
||||||
else if (stage == USB_TRANSFER_STAGE_STATUS) {
|
|
||||||
HALT_UNTIL_DEBUGGING();
|
|
||||||
}
|
|
||||||
return USB_REQUEST_STATUS_OK;
|
|
||||||
|
|
||||||
|
|
||||||
(void)(endpoint);
|
|
||||||
(void)(stage);
|
|
||||||
return USB_REQUEST_STATUS_OK;
|
return USB_REQUEST_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_request_status_t usb_vendor_request(
|
usb_request_status_t usb_class_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) {
|
||||||
usb_endpoint_t* const endpoint,
|
|
||||||
const usb_transfer_stage_t stage)
|
|
||||||
{
|
|
||||||
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
|
|
||||||
|
|
||||||
// volatile uint_fast8_t address = endpoint->address;
|
|
||||||
volatile uint8_t request = endpoint->setup.request;
|
|
||||||
// volatile uint32_t b = 0;
|
|
||||||
|
|
||||||
if (request == 25) { // unknown code
|
|
||||||
return report_magic_scsi(endpoint, stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// b = request + (address << 16);
|
|
||||||
// HALT_UNTIL_DEBUGGING();
|
|
||||||
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_request_status_t usb_class_request(
|
|
||||||
usb_endpoint_t* const endpoint,
|
|
||||||
const usb_transfer_stage_t stage)
|
|
||||||
{
|
|
||||||
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
|
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
|
||||||
|
|
||||||
volatile uint8_t request = endpoint->setup.request;
|
volatile uint8_t request = endpoint->setup.request;
|
||||||
// volatile uint32_t b = 0;
|
|
||||||
|
|
||||||
if (request == 0xFE) {
|
if (request == 0xFE)
|
||||||
return report_max_lun(endpoint, stage);
|
return report_max_lun(endpoint, stage);
|
||||||
}
|
|
||||||
|
|
||||||
// b = request + (address << 16);
|
|
||||||
// HALT_UNTIL_DEBUGGING();
|
|
||||||
|
|
||||||
// if (address == 0x80) {
|
|
||||||
|
|
||||||
// HALT_UNTIL_DEBUGGING();
|
|
||||||
// return USB_REQUEST_STATUS_OK;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else if (address == 0x00) {
|
|
||||||
// if (request == 0xFE) {
|
|
||||||
// return USB_REQUEST_STATUS_OK; // ???????????????????
|
|
||||||
// }
|
|
||||||
// b = request + (address << 16);
|
|
||||||
// HALT_UNTIL_DEBUGGING();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else if (address == 0x02) {
|
|
||||||
// if (request == 0xFE) {
|
|
||||||
// return USB_REQUEST_STATUS_OK; // ???????????????????
|
|
||||||
// }
|
|
||||||
// //return USB_REQUEST_STATUS_OK;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// HALT_UNTIL_DEBUGGING();
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
const usb_request_handlers_t usb_request_handlers = {
|
const usb_request_handlers_t usb_request_handlers = {
|
||||||
.standard = usb_standard_request,
|
.standard = usb_standard_request,
|
||||||
.class = usb_class_request,
|
.class = usb_class_request,
|
||||||
.vendor = usb_vendor_request,
|
.vendor = 0,
|
||||||
.reserved = 0
|
.reserved = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
void usb_configuration_changed(usb_device_t* const device)
|
void usb_configuration_changed(usb_device_t* const device) {
|
||||||
{
|
(void)device;
|
||||||
|
|
||||||
usb_endpoint_init(&usb_endpoint_bulk_in);
|
usb_endpoint_init(&usb_endpoint_bulk_in);
|
||||||
usb_endpoint_init(&usb_endpoint_bulk_out);
|
usb_endpoint_init(&usb_endpoint_bulk_out);
|
||||||
}
|
}
|
||||||
@ -167,7 +52,7 @@ void usb_configuration_changed(usb_device_t* const device)
|
|||||||
void start_usb(void) {
|
void start_usb(void) {
|
||||||
detect_hardware_platform();
|
detect_hardware_platform();
|
||||||
pin_setup();
|
pin_setup();
|
||||||
cpu_clock_init(); // required
|
cpu_clock_init();
|
||||||
|
|
||||||
usb_set_configuration_changed_cb(usb_configuration_changed);
|
usb_set_configuration_changed_cb(usb_configuration_changed);
|
||||||
usb_peripheral_reset();
|
usb_peripheral_reset();
|
||||||
@ -198,6 +83,9 @@ void irq_usb(void) {
|
|||||||
volatile bool transfer_complete = false;
|
volatile bool transfer_complete = false;
|
||||||
void scsi_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred)
|
void scsi_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred)
|
||||||
{
|
{
|
||||||
|
(void)user_data;
|
||||||
|
(void)bytes_transferred;
|
||||||
|
|
||||||
transfer_complete = true;
|
transfer_complete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,18 +94,17 @@ void usb_transfer(void) {
|
|||||||
transfer_complete = false;
|
transfer_complete = false;
|
||||||
usb_transfer_schedule_block(
|
usb_transfer_schedule_block(
|
||||||
&usb_endpoint_bulk_out,
|
&usb_endpoint_bulk_out,
|
||||||
&usb_bulk_buffer[0],
|
&usb_bulk_buffer[0x4000],
|
||||||
USB_TRANSFER_SIZE,
|
USB_TRANSFER_SIZE,
|
||||||
scsi_bulk_transfer_complete,
|
scsi_bulk_transfer_complete,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
while (!transfer_complete);
|
while (!transfer_complete);
|
||||||
|
|
||||||
msd_cbw_t *msd_cbw_data = (msd_cbw_t *) &usb_bulk_buffer[0];
|
msd_cbw_t *msd_cbw_data = (msd_cbw_t *) &usb_bulk_buffer[0x4000];
|
||||||
|
|
||||||
if (msd_cbw_data->signature == MSD_CBW_SIGNATURE){
|
if (msd_cbw_data->signature == MSD_CBW_SIGNATURE){
|
||||||
scsi_command(msd_cbw_data);
|
scsi_command(msd_cbw_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,8 +27,8 @@
|
|||||||
#include <common/usb.h>
|
#include <common/usb.h>
|
||||||
#include <common/usb_request.h>
|
#include <common/usb_request.h>
|
||||||
#include <common/usb_standard_request.h>
|
#include <common/usb_standard_request.h>
|
||||||
#include "usb_device.h"
|
#include <hackrf_usb/usb_device.h>
|
||||||
#include "usb_endpoint.h"
|
#include <hackrf_usb/usb_endpoint.h>
|
||||||
#include <libopencm3/lpc43xx/m4/nvic.h>
|
#include <libopencm3/lpc43xx/m4/nvic.h>
|
||||||
#include <libopencm3/lpc43xx/cgu.h>
|
#include <libopencm3/lpc43xx/cgu.h>
|
||||||
#include "platform_detect.h"
|
#include "platform_detect.h"
|
||||||
|
@ -1,676 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
|
||||||
* Copyright 2012 Jared Boone
|
|
||||||
*
|
|
||||||
* This file is part of HackRF.
|
|
||||||
*
|
|
||||||
* 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, 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; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include <common/usb.h>
|
|
||||||
#include "usb_type.h"
|
|
||||||
#include "usb_queue.h"
|
|
||||||
#include "usb_standard_request.h"
|
|
||||||
|
|
||||||
#include <libopencm3/lpc43xx/creg.h>
|
|
||||||
#include <libopencm3/lpc43xx/m4/nvic.h>
|
|
||||||
#include <libopencm3/lpc43xx/rgu.h>
|
|
||||||
#include <libopencm3/lpc43xx/usb.h>
|
|
||||||
|
|
||||||
#define HALT_UNTIL_DEBUGGING() \
|
|
||||||
while (!((*(volatile uint32_t *)0xE000EDF0) & (1 << 0))) {} \
|
|
||||||
__asm__ __volatile__("bkpt 1")
|
|
||||||
|
|
||||||
|
|
||||||
usb_device_t* usb_device_usb0 = 0;
|
|
||||||
|
|
||||||
usb_queue_head_t usb_qh[12] ATTR_ALIGNED(2048);
|
|
||||||
|
|
||||||
#define USB_QH_INDEX(endpoint_address) \
|
|
||||||
(((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1))
|
|
||||||
|
|
||||||
usb_queue_head_t* usb_queue_head(const uint_fast8_t endpoint_address)
|
|
||||||
{
|
|
||||||
return &usb_qh[USB_QH_INDEX(endpoint_address)];
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_endpoint_t* usb_endpoint_from_address(const uint_fast8_t endpoint_address)
|
|
||||||
{
|
|
||||||
return (usb_endpoint_t*) usb_queue_head(endpoint_address)->_reserved_0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint_fast8_t usb_endpoint_address(
|
|
||||||
const usb_transfer_direction_t direction,
|
|
||||||
const uint_fast8_t number)
|
|
||||||
{
|
|
||||||
return ((direction == USB_TRANSFER_DIRECTION_IN) ? 0x80 : 0x00) + number;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool usb_endpoint_is_in(const uint_fast8_t endpoint_address)
|
|
||||||
{
|
|
||||||
return (endpoint_address & 0x80) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint_fast8_t usb_endpoint_number(const uint_fast8_t endpoint_address)
|
|
||||||
{
|
|
||||||
return (endpoint_address & 0xF);
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_peripheral_reset()
|
|
||||||
{
|
|
||||||
RESET_CTRL0 = RESET_CTRL0_USB0_RST;
|
|
||||||
RESET_CTRL0 = 0;
|
|
||||||
|
|
||||||
while ((RESET_ACTIVE_STATUS0 & RESET_CTRL0_USB0_RST) == 0) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_phy_enable()
|
|
||||||
{
|
|
||||||
CREG_CREG0 &= ~CREG_CREG0_USB0PHY;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_clear_pending_interrupts(const uint32_t mask)
|
|
||||||
{
|
|
||||||
USB0_ENDPTNAK = mask;
|
|
||||||
USB0_ENDPTNAKEN = mask;
|
|
||||||
USB0_USBSTS_D = mask;
|
|
||||||
USB0_ENDPTSETUPSTAT = USB0_ENDPTSETUPSTAT & mask;
|
|
||||||
USB0_ENDPTCOMPLETE = USB0_ENDPTCOMPLETE & mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_clear_all_pending_interrupts()
|
|
||||||
{
|
|
||||||
usb_clear_pending_interrupts(0xFFFFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_wait_for_endpoint_priming_to_finish(const uint32_t mask)
|
|
||||||
{
|
|
||||||
// Wait until controller has parsed new transfer descriptors and prepared
|
|
||||||
// receive buffers.
|
|
||||||
while (USB0_ENDPTPRIME & mask) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_flush_endpoints(const uint32_t mask)
|
|
||||||
{
|
|
||||||
// Clear any primed buffers. If a packet is in progress, that transfer
|
|
||||||
// will continue until completion.
|
|
||||||
USB0_ENDPTFLUSH = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_wait_for_endpoint_flushing_to_finish(const uint32_t mask)
|
|
||||||
{
|
|
||||||
// Wait until controller has flushed all endpoints / cleared any primed
|
|
||||||
// buffers.
|
|
||||||
while (USB0_ENDPTFLUSH & mask) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_flush_primed_endpoints(const uint32_t mask)
|
|
||||||
{
|
|
||||||
usb_wait_for_endpoint_priming_to_finish(mask);
|
|
||||||
usb_flush_endpoints(mask);
|
|
||||||
usb_wait_for_endpoint_flushing_to_finish(mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_flush_all_primed_endpoints()
|
|
||||||
{
|
|
||||||
usb_flush_primed_endpoints(0xFFFFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_endpoint_set_type(
|
|
||||||
const usb_endpoint_t* const endpoint,
|
|
||||||
const usb_transfer_type_t transfer_type)
|
|
||||||
{
|
|
||||||
// NOTE: UM10503 section 23.6.24 "Endpoint 1 to 5 control registers" says
|
|
||||||
// that the disabled side of an endpoint must be set to a non-control type
|
|
||||||
// (e.g. bulk, interrupt, or iso).
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
USB0_ENDPTCTRL(endpoint_number) =
|
|
||||||
(USB0_ENDPTCTRL(endpoint_number) &
|
|
||||||
~(USB0_ENDPTCTRL_TXT1_0_MASK | USB0_ENDPTCTRL_RXT_MASK)) |
|
|
||||||
(USB0_ENDPTCTRL_TXT1_0(transfer_type) |
|
|
||||||
USB0_ENDPTCTRL_RXT(transfer_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_endpoint_enable(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
USB0_ENDPTCTRL(endpoint_number) |=
|
|
||||||
(USB0_ENDPTCTRL_TXE | USB0_ENDPTCTRL_TXR);
|
|
||||||
} else {
|
|
||||||
USB0_ENDPTCTRL(endpoint_number) |=
|
|
||||||
(USB0_ENDPTCTRL_RXE | USB0_ENDPTCTRL_RXR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_endpoint_clear_pending_interrupts(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
usb_clear_pending_interrupts(
|
|
||||||
USB0_ENDPTCOMPLETE_ETCE(1 << endpoint_number));
|
|
||||||
} else {
|
|
||||||
usb_clear_pending_interrupts(
|
|
||||||
USB0_ENDPTCOMPLETE_ERCE(1 << endpoint_number));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_endpoint_disable(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_TXE);
|
|
||||||
} else {
|
|
||||||
USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_RXE);
|
|
||||||
}
|
|
||||||
usb_queue_flush_endpoint(endpoint);
|
|
||||||
usb_endpoint_clear_pending_interrupts(endpoint);
|
|
||||||
usb_endpoint_flush(endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_endpoint_prime(
|
|
||||||
const usb_endpoint_t* const endpoint,
|
|
||||||
usb_transfer_descriptor_t* const first_td)
|
|
||||||
{
|
|
||||||
usb_queue_head_t* const qh = usb_queue_head(endpoint->address);
|
|
||||||
|
|
||||||
qh->next_dtd_pointer = first_td;
|
|
||||||
qh->total_bytes &=
|
|
||||||
~(USB_TD_DTD_TOKEN_STATUS_ACTIVE | USB_TD_DTD_TOKEN_STATUS_HALTED);
|
|
||||||
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
USB0_ENDPTPRIME = USB0_ENDPTPRIME_PETB(1 << endpoint_number);
|
|
||||||
} else {
|
|
||||||
USB0_ENDPTPRIME = USB0_ENDPTPRIME_PERB(1 << endpoint_number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool usb_endpoint_is_priming(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PETB(1 << endpoint_number);
|
|
||||||
} else {
|
|
||||||
return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schedule an already filled-in transfer descriptor for execution on
|
|
||||||
// the given endpoint, waiting until the endpoint has finished.
|
|
||||||
void usb_endpoint_schedule_wait(
|
|
||||||
const usb_endpoint_t* const endpoint,
|
|
||||||
usb_transfer_descriptor_t* const td)
|
|
||||||
{
|
|
||||||
// Ensure that endpoint is ready to be primed.
|
|
||||||
// It may have been flushed due to an aborted transaction.
|
|
||||||
// TODO: This should be preceded by a flush?
|
|
||||||
while (usb_endpoint_is_ready(endpoint)) {}
|
|
||||||
|
|
||||||
td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
|
||||||
|
|
||||||
usb_endpoint_prime(endpoint, td);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schedule an already filled-in transfer descriptor for execution on
|
|
||||||
// the given endpoint, appending to the end of the endpoint's queue if
|
|
||||||
// there are pending TDs. Note that this requires that one knows the
|
|
||||||
// tail of the endpoint's TD queue. Moreover, the user is responsible
|
|
||||||
// for setting the TERMINATE bit of next_dtd_pointer if needed.
|
|
||||||
void usb_endpoint_schedule_append(
|
|
||||||
const usb_endpoint_t* const endpoint,
|
|
||||||
usb_transfer_descriptor_t* const tail_td,
|
|
||||||
usb_transfer_descriptor_t* const new_td)
|
|
||||||
{
|
|
||||||
bool done;
|
|
||||||
|
|
||||||
tail_td->next_dtd_pointer = new_td;
|
|
||||||
|
|
||||||
if (usb_endpoint_is_priming(endpoint)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW;
|
|
||||||
done = usb_endpoint_is_ready(endpoint);
|
|
||||||
} while (!(USB0_USBCMD_D & USB0_USBCMD_D_ATDTW));
|
|
||||||
|
|
||||||
USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW;
|
|
||||||
if (!done) {
|
|
||||||
usb_endpoint_prime(endpoint, new_td);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_endpoint_flush(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
usb_queue_flush_endpoint(endpoint);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FETB(1 << endpoint_number));
|
|
||||||
} else {
|
|
||||||
usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FERB(1 << endpoint_number));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
static bool usb_endpoint_is_flushing(
|
|
||||||
const usb_endpoint_t* const endpoint
|
|
||||||
) {
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
|
||||||
return USB0_ENDPTFLUSH & USB0_ENDPTFLUSH_FETB(1 << endpoint_number);
|
|
||||||
} else {
|
|
||||||
return USB0_ENDPTFLUSH & USB0_ENDPTFLUSH_FERB(1 << endpoint_number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
bool usb_endpoint_is_ready(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
return USB0_ENDPTSTAT & USB0_ENDPTSTAT_ETBR(1 << endpoint_number);
|
|
||||||
} else {
|
|
||||||
return USB0_ENDPTSTAT & USB0_ENDPTSTAT_ERBR(1 << endpoint_number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool usb_endpoint_is_complete(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
return USB0_ENDPTCOMPLETE & USB0_ENDPTCOMPLETE_ETCE(1 << endpoint_number);
|
|
||||||
} else {
|
|
||||||
return USB0_ENDPTCOMPLETE & USB0_ENDPTCOMPLETE_ERCE(1 << endpoint_number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_endpoint_stall(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
// Endpoint is to be stalled as a pair -- both OUT and IN.
|
|
||||||
// See UM10503 section 23.10.5.2 "Stalling"
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_RXS | USB0_ENDPTCTRL_TXS);
|
|
||||||
|
|
||||||
// TODO: Also need to reset data toggle in both directions?
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_endpoint_reset_data_toggle(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
|
||||||
if (usb_endpoint_is_in(endpoint->address)) {
|
|
||||||
USB0_ENDPTCTRL(endpoint_number) |= USB0_ENDPTCTRL_TXR;
|
|
||||||
} else {
|
|
||||||
USB0_ENDPTCTRL(endpoint_number) |= USB0_ENDPTCTRL_RXR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_controller_run()
|
|
||||||
{
|
|
||||||
USB0_USBCMD_D |= USB0_USBCMD_D_RS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_controller_stop()
|
|
||||||
{
|
|
||||||
USB0_USBCMD_D &= ~USB0_USBCMD_D_RS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint_fast8_t usb_controller_is_resetting()
|
|
||||||
{
|
|
||||||
return (USB0_USBCMD_D & USB0_USBCMD_D_RST) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_controller_set_device_mode()
|
|
||||||
{
|
|
||||||
// Set USB0 peripheral mode
|
|
||||||
USB0_USBMODE_D = USB0_USBMODE_D_CM1_0(2);
|
|
||||||
|
|
||||||
// Set device-related OTG flags
|
|
||||||
// OTG termination: controls pull-down on USB_DM
|
|
||||||
USB0_OTGSC = USB0_OTGSC_OT;
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_speed_t usb_speed(const usb_device_t* const device)
|
|
||||||
{
|
|
||||||
if (device == usb_device_usb0) {
|
|
||||||
switch (USB0_PORTSC1_D & USB0_PORTSC1_D_PSPD_MASK) {
|
|
||||||
case USB0_PORTSC1_D_PSPD(0):
|
|
||||||
return USB_SPEED_FULL;
|
|
||||||
|
|
||||||
case USB0_PORTSC1_D_PSPD(2):
|
|
||||||
return USB_SPEED_HIGH;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// TODO: What to do/return here? Is this even possible?
|
|
||||||
return USB_SPEED_FULL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: This should not be possible with a more class-like
|
|
||||||
// implementation.
|
|
||||||
return USB_SPEED_FULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_clear_status(const uint32_t status)
|
|
||||||
{
|
|
||||||
USB0_USBSTS_D = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t usb_get_status()
|
|
||||||
{
|
|
||||||
// Mask status flags with enabled flag interrupts.
|
|
||||||
const uint32_t status = USB0_USBSTS_D & USB0_USBINTR_D;
|
|
||||||
|
|
||||||
// Clear flags that were just read, leaving alone any flags that
|
|
||||||
// were just set (after the read). It's important to read and
|
|
||||||
// reset flags atomically! :-)
|
|
||||||
usb_clear_status(status);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_clear_endpoint_setup_status(const uint32_t endpoint_setup_status)
|
|
||||||
{
|
|
||||||
USB0_ENDPTSETUPSTAT = endpoint_setup_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t usb_get_endpoint_setup_status()
|
|
||||||
{
|
|
||||||
return USB0_ENDPTSETUPSTAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_clear_endpoint_complete(const uint32_t endpoint_complete)
|
|
||||||
{
|
|
||||||
USB0_ENDPTCOMPLETE = endpoint_complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t usb_get_endpoint_complete()
|
|
||||||
{
|
|
||||||
return USB0_ENDPTCOMPLETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_disable_all_endpoints()
|
|
||||||
{
|
|
||||||
// Endpoint 0 is always enabled. TODO: So why set ENDPTCTRL0?
|
|
||||||
USB0_ENDPTCTRL0 &= ~(USB0_ENDPTCTRL0_RXE | USB0_ENDPTCTRL0_TXE);
|
|
||||||
USB0_ENDPTCTRL1 &= ~(USB0_ENDPTCTRL1_RXE | USB0_ENDPTCTRL1_TXE);
|
|
||||||
USB0_ENDPTCTRL2 &= ~(USB0_ENDPTCTRL2_RXE | USB0_ENDPTCTRL2_TXE);
|
|
||||||
USB0_ENDPTCTRL3 &= ~(USB0_ENDPTCTRL3_RXE | USB0_ENDPTCTRL3_TXE);
|
|
||||||
USB0_ENDPTCTRL4 &= ~(USB0_ENDPTCTRL4_RXE | USB0_ENDPTCTRL4_TXE);
|
|
||||||
USB0_ENDPTCTRL5 &= ~(USB0_ENDPTCTRL5_RXE | USB0_ENDPTCTRL5_TXE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_set_address_immediate(
|
|
||||||
const usb_device_t* const device,
|
|
||||||
const uint_fast8_t address)
|
|
||||||
{
|
|
||||||
if (device == usb_device_usb0) {
|
|
||||||
USB0_DEVICEADDR = USB0_DEVICEADDR_USBADR(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_set_address_deferred(const usb_device_t* const device, const uint_fast8_t address)
|
|
||||||
{
|
|
||||||
if (device == usb_device_usb0) {
|
|
||||||
USB0_DEVICEADDR =
|
|
||||||
USB0_DEVICEADDR_USBADR(address) | USB0_DEVICEADDR_USBADRA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_reset_all_endpoints()
|
|
||||||
{
|
|
||||||
usb_disable_all_endpoints();
|
|
||||||
usb_clear_all_pending_interrupts();
|
|
||||||
usb_flush_all_primed_endpoints();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_controller_reset()
|
|
||||||
{
|
|
||||||
// TODO: Good to disable some USB interrupts to avoid priming new
|
|
||||||
// new endpoints before the controller is reset?
|
|
||||||
usb_reset_all_endpoints();
|
|
||||||
usb_controller_stop();
|
|
||||||
|
|
||||||
// Reset controller. Resets internal pipelines, timers, counters, state
|
|
||||||
// machines to initial values. Not recommended when device is in attached
|
|
||||||
// state -- effect on attached host is undefined. Detach first by flushing
|
|
||||||
// all primed endpoints and stopping controller.
|
|
||||||
USB0_USBCMD_D = USB0_USBCMD_D_RST;
|
|
||||||
|
|
||||||
while (usb_controller_is_resetting()) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_bus_reset(usb_device_t* const device)
|
|
||||||
{
|
|
||||||
// According to UM10503 v1.4 section 23.10.3 "Bus reset":
|
|
||||||
usb_reset_all_endpoints();
|
|
||||||
usb_set_address_immediate(device, 0);
|
|
||||||
usb_set_configuration(device, 0);
|
|
||||||
|
|
||||||
// TODO: Enable endpoint 0, which might not actually be necessary,
|
|
||||||
// as the datasheet claims it can't be disabled.
|
|
||||||
|
|
||||||
//wait_ms(3);
|
|
||||||
//
|
|
||||||
//if( USB0_PORTSC1 & USB0_PORTSC1_PR ) {
|
|
||||||
// // Port still is in the reset state.
|
|
||||||
//} else {
|
|
||||||
// usb_hardware_reset();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_interrupt_enable(usb_device_t* const device)
|
|
||||||
{
|
|
||||||
if (device == usb_device_usb0) {
|
|
||||||
nvic_enable_irq(NVIC_USB0_IRQ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_device_init(const uint_fast8_t device_ordinal, usb_device_t* const device)
|
|
||||||
{
|
|
||||||
if (device_ordinal == 0) {
|
|
||||||
usb_device_usb0 = device;
|
|
||||||
|
|
||||||
usb_phy_enable();
|
|
||||||
usb_controller_reset();
|
|
||||||
usb_controller_set_device_mode();
|
|
||||||
|
|
||||||
// Set interrupt threshold interval to 0
|
|
||||||
USB0_USBCMD_D &= ~USB0_USBCMD_D_ITC_MASK;
|
|
||||||
|
|
||||||
// Configure endpoint list address
|
|
||||||
USB0_ENDPOINTLISTADDR = (uint32_t) usb_qh;
|
|
||||||
|
|
||||||
// Enable interrupts
|
|
||||||
USB0_USBINTR_D = USB0_USBINTR_D_UE | USB0_USBINTR_D_UEE |
|
|
||||||
USB0_USBINTR_D_PCE |
|
|
||||||
USB0_USBINTR_D_URE
|
|
||||||
//| USB0_USBINTR_D_SRE
|
|
||||||
| USB0_USBINTR_D_SLE
|
|
||||||
//| USB0_USBINTR_D_NAKE
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_run(usb_device_t* const device)
|
|
||||||
{
|
|
||||||
usb_interrupt_enable(device);
|
|
||||||
usb_controller_run(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copy_setup(usb_setup_t* const dst, const volatile uint8_t* const src)
|
|
||||||
{
|
|
||||||
dst->request_type = src[0];
|
|
||||||
dst->request = src[1];
|
|
||||||
dst->value_l = src[2];
|
|
||||||
dst->value_h = src[3];
|
|
||||||
dst->index_l = src[4];
|
|
||||||
dst->index_h = src[5];
|
|
||||||
dst->length_l = src[6];
|
|
||||||
dst->length_h = src[7];
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_endpoint_init(const usb_endpoint_t* const endpoint)
|
|
||||||
{
|
|
||||||
usb_endpoint_flush(endpoint);
|
|
||||||
|
|
||||||
uint_fast16_t max_packet_size = endpoint->device->descriptor[7];
|
|
||||||
usb_transfer_type_t transfer_type = USB_TRANSFER_TYPE_CONTROL;
|
|
||||||
const uint8_t* const endpoint_descriptor = usb_endpoint_descriptor(endpoint);
|
|
||||||
if (endpoint_descriptor) {
|
|
||||||
max_packet_size =
|
|
||||||
usb_endpoint_descriptor_max_packet_size(endpoint_descriptor);
|
|
||||||
transfer_type =
|
|
||||||
usb_endpoint_descriptor_transfer_type(endpoint_descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: There are more capabilities to adjust based on the endpoint
|
|
||||||
// descriptor.
|
|
||||||
usb_queue_head_t* const qh = usb_queue_head(endpoint->address);
|
|
||||||
qh->capabilities = USB_QH_CAPABILITIES_MULT(0) | USB_QH_CAPABILITIES_ZLT |
|
|
||||||
USB_QH_CAPABILITIES_MPL(max_packet_size) |
|
|
||||||
((transfer_type == USB_TRANSFER_TYPE_CONTROL) ? USB_QH_CAPABILITIES_IOS :
|
|
||||||
0);
|
|
||||||
qh->current_dtd_pointer = 0;
|
|
||||||
qh->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
|
||||||
qh->total_bytes = USB_TD_DTD_TOKEN_TOTAL_BYTES(0) | USB_TD_DTD_TOKEN_MULTO(0);
|
|
||||||
qh->buffer_pointer_page[0] = 0;
|
|
||||||
qh->buffer_pointer_page[1] = 0;
|
|
||||||
qh->buffer_pointer_page[2] = 0;
|
|
||||||
qh->buffer_pointer_page[3] = 0;
|
|
||||||
qh->buffer_pointer_page[4] = 0;
|
|
||||||
|
|
||||||
// This is how we look up an endpoint structure from an endpoint address:
|
|
||||||
qh->_reserved_0 = (uint32_t) endpoint;
|
|
||||||
|
|
||||||
// TODO: Should NAK be enabled? I'm kinda squishy on this...
|
|
||||||
//USB0_ENDPTNAKEN |=
|
|
||||||
// USB0_ENDPTNAKEN_EPRNE(1 << endpoint_out->number);
|
|
||||||
|
|
||||||
usb_endpoint_set_type(endpoint, transfer_type);
|
|
||||||
|
|
||||||
usb_endpoint_enable(endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_check_for_setup_events() {
|
|
||||||
const uint32_t endptsetupstat = usb_get_endpoint_setup_status();
|
|
||||||
if (endptsetupstat) {
|
|
||||||
for (uint_fast8_t i = 0; i < 6; i++) {
|
|
||||||
const uint32_t endptsetupstat_bit = USB0_ENDPTSETUPSTAT_ENDPTSETUPSTAT(1 << i);
|
|
||||||
if (endptsetupstat & endptsetupstat_bit) {
|
|
||||||
usb_endpoint_t* const endpoint = usb_endpoint_from_address(usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i));
|
|
||||||
if (endpoint && endpoint->setup_complete) {
|
|
||||||
usb_queue_head_t *head = usb_queue_head(endpoint->address);
|
|
||||||
|
|
||||||
//HALT_UNTIL_DEBUGGING();
|
|
||||||
|
|
||||||
copy_setup(&endpoint->setup, head->setup);
|
|
||||||
// TODO: Clean up this duplicated effort by providing
|
|
||||||
// a cleaner way to get the SETUP data.
|
|
||||||
copy_setup(&endpoint->in->setup, head->setup);
|
|
||||||
|
|
||||||
usb_clear_endpoint_setup_status(endptsetupstat_bit);
|
|
||||||
endpoint->setup_complete(endpoint);
|
|
||||||
} else {
|
|
||||||
usb_clear_endpoint_setup_status(endptsetupstat_bit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_check_for_transfer_events() {
|
|
||||||
const uint32_t endptcomplete = usb_get_endpoint_complete();
|
|
||||||
|
|
||||||
if (endptcomplete) {
|
|
||||||
for (uint_fast8_t i = 0; i < 6; i++) {
|
|
||||||
const uint32_t endptcomplete_out_bit = USB0_ENDPTCOMPLETE_ERCE(1 << i);
|
|
||||||
|
|
||||||
if (endptcomplete & endptcomplete_out_bit) {
|
|
||||||
usb_clear_endpoint_complete(endptcomplete_out_bit);
|
|
||||||
usb_endpoint_t* const endpoint = usb_endpoint_from_address(usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i));
|
|
||||||
if (endpoint && endpoint->transfer_complete) {
|
|
||||||
endpoint->transfer_complete(endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32_t endptcomplete_in_bit = USB0_ENDPTCOMPLETE_ETCE(1 << i);
|
|
||||||
|
|
||||||
if (endptcomplete & endptcomplete_in_bit) {
|
|
||||||
usb_clear_endpoint_complete(endptcomplete_in_bit);
|
|
||||||
usb_endpoint_t* const endpoint = usb_endpoint_from_address(usb_endpoint_address(USB_TRANSFER_DIRECTION_IN, i));
|
|
||||||
if (endpoint && endpoint->transfer_complete) {
|
|
||||||
endpoint->transfer_complete(endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb0_isr()
|
|
||||||
{
|
|
||||||
const uint32_t status = usb_get_status();
|
|
||||||
|
|
||||||
if (status == 0) {
|
|
||||||
// Nothing to do.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & USB0_USBSTS_D_UI) {
|
|
||||||
// USB:
|
|
||||||
// - Completed transaction transfer descriptor has IOC set.
|
|
||||||
// - Short packet detected.
|
|
||||||
// - SETUP packet received.
|
|
||||||
|
|
||||||
usb_check_for_setup_events();
|
|
||||||
usb_check_for_transfer_events();
|
|
||||||
|
|
||||||
// TODO: Reset ignored ENDPTSETUPSTAT and ENDPTCOMPLETE flags?
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & USB0_USBSTS_D_SRI) {
|
|
||||||
// Start Of Frame received.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & USB0_USBSTS_D_PCI) {
|
|
||||||
// Port change detect:
|
|
||||||
// Port controller entered full- or high-speed operational state.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & USB0_USBSTS_D_SLI) {
|
|
||||||
// Device controller suspend.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & USB0_USBSTS_D_URI) {
|
|
||||||
// USB reset received.
|
|
||||||
usb_bus_reset(usb_device_usb0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & USB0_USBSTS_D_UEI) {
|
|
||||||
// USB error:
|
|
||||||
// Completion of a USB transaction resulted in an error condition.
|
|
||||||
// Set along with USBINT if the TD on which the error interrupt
|
|
||||||
// occurred also had its interrupt on complete (IOC) bit set.
|
|
||||||
// The device controller detects resume signalling only.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & USB0_USBSTS_D_NAKI) {
|
|
||||||
// Both the TX/RX endpoint NAK bit and corresponding TX/RX endpoint
|
|
||||||
// NAK enable bit are set.
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
|
||||||
* Copyright 2012 Jared Boone
|
|
||||||
* Copyright 2013 Benjamin Vernoux
|
|
||||||
*
|
|
||||||
* This file is part of HackRF.
|
|
||||||
*
|
|
||||||
* 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, 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; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "usb_device.h"
|
|
||||||
|
|
||||||
#include <usb_type.h>
|
|
||||||
|
|
||||||
#include "usb_descriptor.h"
|
|
||||||
|
|
||||||
usb_configuration_t usb_configuration_high_speed = {
|
|
||||||
.number = 1,
|
|
||||||
.speed = USB_SPEED_HIGH,
|
|
||||||
.descriptor = usb_descriptor_configuration_high_speed,
|
|
||||||
};
|
|
||||||
|
|
||||||
usb_configuration_t usb_configuration_full_speed = {
|
|
||||||
.number = 1,
|
|
||||||
.speed = USB_SPEED_FULL,
|
|
||||||
.descriptor = usb_descriptor_configuration_full_speed,
|
|
||||||
};
|
|
||||||
|
|
||||||
usb_configuration_t* usb_configurations[] = {
|
|
||||||
&usb_configuration_high_speed,
|
|
||||||
&usb_configuration_full_speed,
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
|
|
||||||
usb_device_t usb_device = {
|
|
||||||
.descriptor = usb_descriptor_device,
|
|
||||||
.descriptor_strings = usb_descriptor_strings,
|
|
||||||
.qualifier_descriptor = usb_descriptor_device_qualifier,
|
|
||||||
.configurations = &usb_configurations,
|
|
||||||
.configuration = 0,
|
|
||||||
.wcid_string_descriptor = wcid_string_descriptor,
|
|
||||||
.wcid_feature_descriptor = wcid_feature_descriptor,
|
|
||||||
};
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2013 Great Scott Gadgets <info@greatscottgadgets.com>
|
|
||||||
* Copyright 2012 Jared Boone
|
|
||||||
* Copyright 2013 Benjamin Vernoux
|
|
||||||
*
|
|
||||||
* This file is part of HackRF.
|
|
||||||
*
|
|
||||||
* 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, 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; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __USB_DEVICE_H__
|
|
||||||
#define __USB_DEVICE_H__
|
|
||||||
|
|
||||||
#include <usb_type.h>
|
|
||||||
|
|
||||||
extern usb_device_t usb_device;
|
|
||||||
|
|
||||||
#endif /* end of include guard: __USB_DEVICE_H__ */
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
|
||||||
* Copyright 2012 Jared Boone
|
|
||||||
* Copyright 2013 Benjamin Vernoux
|
|
||||||
*
|
|
||||||
* This file is part of HackRF.
|
|
||||||
*
|
|
||||||
* 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, 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; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "usb_endpoint.h"
|
|
||||||
|
|
||||||
#include <usb_request.h>
|
|
||||||
|
|
||||||
#include "usb_device.h"
|
|
||||||
|
|
||||||
usb_endpoint_t usb_endpoint_control_out = {
|
|
||||||
.address = 0x00,
|
|
||||||
.device = &usb_device,
|
|
||||||
.in = &usb_endpoint_control_in,
|
|
||||||
.out = &usb_endpoint_control_out,
|
|
||||||
.setup_complete = usb_setup_complete,
|
|
||||||
.transfer_complete = usb_control_out_complete,
|
|
||||||
};
|
|
||||||
USB_DEFINE_QUEUE(usb_endpoint_control_out, 4);
|
|
||||||
|
|
||||||
usb_endpoint_t usb_endpoint_control_in = {
|
|
||||||
.address = 0x80,
|
|
||||||
.device = &usb_device,
|
|
||||||
.in = &usb_endpoint_control_in,
|
|
||||||
.out = &usb_endpoint_control_out,
|
|
||||||
.setup_complete = 0,
|
|
||||||
.transfer_complete = usb_control_in_complete,
|
|
||||||
};
|
|
||||||
static USB_DEFINE_QUEUE(usb_endpoint_control_in, 4);
|
|
||||||
|
|
||||||
// NOTE: Endpoint number for IN and OUT are different. I wish I had some
|
|
||||||
// evidence that having BULK IN and OUT on separate endpoint numbers was
|
|
||||||
// actually a good idea. Seems like everybody does it that way, but why?
|
|
||||||
|
|
||||||
usb_endpoint_t usb_endpoint_bulk_in = {
|
|
||||||
.address = 0x81,
|
|
||||||
.device = &usb_device,
|
|
||||||
.in = &usb_endpoint_bulk_in,
|
|
||||||
.out = 0,
|
|
||||||
.setup_complete = 0,
|
|
||||||
.transfer_complete = usb_queue_transfer_complete};
|
|
||||||
static USB_DEFINE_QUEUE(usb_endpoint_bulk_in, 1);
|
|
||||||
|
|
||||||
usb_endpoint_t usb_endpoint_bulk_out = {
|
|
||||||
.address = 0x02,
|
|
||||||
.device = &usb_device,
|
|
||||||
.in = 0,
|
|
||||||
.out = &usb_endpoint_bulk_out,
|
|
||||||
.setup_complete = 0,
|
|
||||||
.transfer_complete = usb_queue_transfer_complete};
|
|
||||||
static USB_DEFINE_QUEUE(usb_endpoint_bulk_out, 1);
|
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2013 Great Scott Gadgets <info@greatscottgadgets.com>
|
|
||||||
* Copyright 2012 Jared Boone
|
|
||||||
* Copyright 2013 Benjamin Vernoux
|
|
||||||
*
|
|
||||||
* This file is part of HackRF.
|
|
||||||
*
|
|
||||||
* 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, 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; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __USB_ENDPOINT_H__
|
|
||||||
#define __USB_ENDPOINT_H__
|
|
||||||
|
|
||||||
#include <usb_type.h>
|
|
||||||
#include <usb_queue.h>
|
|
||||||
|
|
||||||
extern usb_endpoint_t usb_endpoint_control_out;
|
|
||||||
extern USB_DECLARE_QUEUE(usb_endpoint_control_out);
|
|
||||||
|
|
||||||
extern usb_endpoint_t usb_endpoint_control_in;
|
|
||||||
extern USB_DECLARE_QUEUE(usb_endpoint_control_in);
|
|
||||||
|
|
||||||
extern usb_endpoint_t usb_endpoint_bulk_in;
|
|
||||||
extern USB_DECLARE_QUEUE(usb_endpoint_bulk_in);
|
|
||||||
|
|
||||||
extern usb_endpoint_t usb_endpoint_bulk_out;
|
|
||||||
extern USB_DECLARE_QUEUE(usb_endpoint_bulk_out);
|
|
||||||
|
|
||||||
#endif /* end of include guard: __USB_ENDPOINT_H__ */
|
|
Loading…
Reference in New Issue
Block a user