instead of having each HUB have 7 buffers, which can eat up space. We have each main object contribute currently one string buffer, which than when we initialize a Device_t we try to allocate one for it, likewise we release it when the Device is released. Hopefully less memory needed. Also updated such that the HIDInput classes can not retrieve these strings. Changed test program to now also have list of HIDInput objects and when I detect a new one, I again print out info on it...main
// your best effort to read chapter 4 before asking USB questions! | // your best effort to read chapter 4 before asking USB questions! | ||||
#define USBHOST_PRINT_DEBUG | |||||
//#define USBHOST_PRINT_DEBUG | |||||
/************************************************/ | /************************************************/ | ||||
/* Data Types */ | /* Data Types */ | ||||
}; | }; | ||||
} setup_t; | } setup_t; | ||||
typedef struct { | |||||
enum {STRING_BUF_SIZE=50}; | |||||
enum {STR_ID_MAN=0, STR_ID_PROD, STR_ID_SERIAL, STR_ID_CNT}; | |||||
uint8_t iStrings[STR_ID_CNT]; // Index into array for the three indexes | |||||
uint8_t buffer[STRING_BUF_SIZE]; | |||||
} strbuf_t; | |||||
#define DEVICE_STRUCT_STRING_BUF_SIZE 50 | |||||
// Device_t holds all the information about a USB device | // Device_t holds all the information about a USB device | ||||
#define DEVICE_STRUCT_STRING_BUF_SIZE 48 | |||||
struct Device_struct { | struct Device_struct { | ||||
Pipe_t *control_pipe; | Pipe_t *control_pipe; | ||||
Pipe_t *data_pipes; | Pipe_t *data_pipes; | ||||
Device_t *next; | Device_t *next; | ||||
USBDriver *drivers; | USBDriver *drivers; | ||||
strbuf_t *strbuf; | |||||
uint8_t speed; // 0=12, 1=1.5, 2=480 Mbit/sec | uint8_t speed; // 0=12, 1=1.5, 2=480 Mbit/sec | ||||
uint8_t address; | uint8_t address; | ||||
uint8_t hub_address; | uint8_t hub_address; | ||||
uint16_t idVendor; | uint16_t idVendor; | ||||
uint16_t idProduct; | uint16_t idProduct; | ||||
uint16_t LanguageID; | uint16_t LanguageID; | ||||
uint8_t string_buf[DEVICE_STRUCT_STRING_BUF_SIZE]; // Probably want a place to allocate fewer of these... | |||||
uint8_t iStrings[3]; // 3 indexes - vendor string, product string, serial number. | |||||
}; | }; | ||||
// Pipe_t holes all information about each USB endpoint/pipe | // Pipe_t holes all information about each USB endpoint/pipe | ||||
static void contribute_Devices(Device_t *devices, uint32_t num); | static void contribute_Devices(Device_t *devices, uint32_t num); | ||||
static void contribute_Pipes(Pipe_t *pipes, uint32_t num); | static void contribute_Pipes(Pipe_t *pipes, uint32_t num); | ||||
static void contribute_Transfers(Transfer_t *transfers, uint32_t num); | static void contribute_Transfers(Transfer_t *transfers, uint32_t num); | ||||
static void contribute_String_Buffers(strbuf_t *strbuf, uint32_t num); | |||||
static volatile bool enumeration_busy; | static volatile bool enumeration_busy; | ||||
private: | private: | ||||
static void isr(); | static void isr(); | ||||
static void free_Pipe(Pipe_t *q); | static void free_Pipe(Pipe_t *q); | ||||
static Transfer_t * allocate_Transfer(void); | static Transfer_t * allocate_Transfer(void); | ||||
static void free_Transfer(Transfer_t *q); | static void free_Transfer(Transfer_t *q); | ||||
static strbuf_t * allocate_string_buffer(void); | |||||
static void free_string_buffer(strbuf_t *strbuf); | |||||
static bool allocate_interrupt_pipe_bandwidth(Pipe_t *pipe, | static bool allocate_interrupt_pipe_bandwidth(Pipe_t *pipe, | ||||
uint32_t maxlen, uint32_t interval); | uint32_t maxlen, uint32_t interval); | ||||
static void add_qh_to_periodic_schedule(Pipe_t *pipe); | static void add_qh_to_periodic_schedule(Pipe_t *pipe); | ||||
uint16_t idVendor() { return (device != nullptr) ? device->idVendor : 0; } | uint16_t idVendor() { return (device != nullptr) ? device->idVendor : 0; } | ||||
uint16_t idProduct() { return (device != nullptr) ? device->idProduct : 0; } | uint16_t idProduct() { return (device != nullptr) ? device->idProduct : 0; } | ||||
const uint8_t *manufacturer() { return (device != nullptr) ? &(device->string_buf[device->iStrings[0]]) : nullptr; } | |||||
const uint8_t *product() { return (device != nullptr) ? &(device->string_buf[device->iStrings[1]]) : nullptr; } | |||||
const uint8_t *serialNumber() { return (device != nullptr) ? &(device->string_buf[device->iStrings[2]]) : nullptr; } | |||||
const uint8_t *manufacturer() | |||||
{ return ((device == nullptr) || (device->strbuf == nullptr)) ? nullptr : &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; } | |||||
const uint8_t *product() | |||||
{ return ((device == nullptr) || (device->strbuf == nullptr)) ? nullptr : &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; } | |||||
const uint8_t *serialNumber() | |||||
{ return ((device == nullptr) || (device->strbuf == nullptr)) ? nullptr : &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; } | |||||
// TODO: user-level functions | // TODO: user-level functions | ||||
// check if device is bound/active/online | // check if device is bound/active/online | ||||
// wish to claim any device or interface (eg, if getting data | // wish to claim any device or interface (eg, if getting data | ||||
// from the HID parser). | // from the HID parser). | ||||
Device_t *device; | Device_t *device; | ||||
friend class USBHost; | friend class USBHost; | ||||
}; | }; | ||||
operator bool() { return (mydevice != nullptr); } | operator bool() { return (mydevice != nullptr); } | ||||
uint16_t idVendor() { return (mydevice != nullptr) ? mydevice->idVendor : 0; } | uint16_t idVendor() { return (mydevice != nullptr) ? mydevice->idVendor : 0; } | ||||
uint16_t idProduct() { return (mydevice != nullptr) ? mydevice->idProduct : 0; } | uint16_t idProduct() { return (mydevice != nullptr) ? mydevice->idProduct : 0; } | ||||
const uint8_t *manufacturer() | |||||
{ return ((mydevice == nullptr) || (mydevice->strbuf == nullptr)) ? nullptr : &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; } | |||||
const uint8_t *product() | |||||
{ return ((mydevice == nullptr) || (mydevice->strbuf == nullptr)) ? nullptr : &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; } | |||||
const uint8_t *serialNumber() | |||||
{ return ((mydevice == nullptr) || (mydevice->strbuf == nullptr)) ? nullptr : &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; } | |||||
private: | private: | ||||
virtual bool claim_collection(Device_t *dev, uint32_t topusage); | virtual bool claim_collection(Device_t *dev, uint32_t topusage); | ||||
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); | virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); | ||||
Device_t mydevices[MAXPORTS]; | Device_t mydevices[MAXPORTS]; | ||||
Pipe_t mypipes[2] __attribute__ ((aligned(32))); | Pipe_t mypipes[2] __attribute__ ((aligned(32))); | ||||
Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | ||||
strbuf_t mystring_bufs[1]; | |||||
USBDriverTimer debouncetimer; | USBDriverTimer debouncetimer; | ||||
USBDriverTimer resettimer; | USBDriverTimer resettimer; | ||||
setup_t setup; | setup_t setup; | ||||
bool use_report_id; | bool use_report_id; | ||||
Pipe_t mypipes[3] __attribute__ ((aligned(32))); | Pipe_t mypipes[3] __attribute__ ((aligned(32))); | ||||
Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | ||||
strbuf_t mystring_bufs[1]; | |||||
}; | }; | ||||
bool processing_new_data_ = false; | bool processing_new_data_ = false; | ||||
Pipe_t mypipes[2] __attribute__ ((aligned(32))); | Pipe_t mypipes[2] __attribute__ ((aligned(32))); | ||||
Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | ||||
strbuf_t mystring_bufs[1]; | |||||
}; | }; | ||||
class MIDIDevice : public USBDriver { | class MIDIDevice : public USBDriver { | ||||
void (*handleTimeCodeQuarterFrame)(uint16_t data); | void (*handleTimeCodeQuarterFrame)(uint16_t data); | ||||
Pipe_t mypipes[3] __attribute__ ((aligned(32))); | Pipe_t mypipes[3] __attribute__ ((aligned(32))); | ||||
Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | ||||
strbuf_t mystring_bufs[1]; | |||||
}; | }; | ||||
private: | private: | ||||
Pipe_t mypipes[3] __attribute__ ((aligned(32))); | Pipe_t mypipes[3] __attribute__ ((aligned(32))); | ||||
Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | ||||
strbuf_t mystring_bufs[1]; | |||||
USBDriverTimer txtimer; | USBDriverTimer txtimer; | ||||
uint32_t bigbuffer[(BUFFER_SIZE+3)/4]; | uint32_t bigbuffer[(BUFFER_SIZE+3)/4]; | ||||
setup_t setup; | setup_t setup; | ||||
private: | private: | ||||
Pipe_t mypipes[2] __attribute__ ((aligned(32))); | Pipe_t mypipes[2] __attribute__ ((aligned(32))); | ||||
Transfer_t mytransfers[3] __attribute__ ((aligned(32))); | Transfer_t mytransfers[3] __attribute__ ((aligned(32))); | ||||
strbuf_t mystring_bufs[1]; | |||||
//USBDriverTimer txtimer; | //USBDriverTimer txtimer; | ||||
USBDriverTimer updatetimer; | USBDriverTimer updatetimer; | ||||
Pipe_t *rxpipe; | Pipe_t *rxpipe; |
{ | { | ||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | ||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | ||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||||
driver_ready_for_device(this); | driver_ready_for_device(this); | ||||
callbackFunc = NULL; | callbackFunc = NULL; | ||||
} | } |
free_Device(dev); | free_Device(dev); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
dev->strbuf = allocate_string_buffer(); // try to allocate a string buffer; | |||||
dev->control_pipe->callback_function = &enumeration; | dev->control_pipe->callback_function = &enumeration; | ||||
dev->control_pipe->direction = 1; // 1=IN | dev->control_pipe->direction = 1; // 1=IN | ||||
// Here is where the enumeration process officially begins. | // Here is where the enumeration process officially begins. | ||||
dev->enum_state = 4; | dev->enum_state = 4; | ||||
return; | return; | ||||
case 4: // parse Language ID | case 4: // parse Language ID | ||||
dev->iStrings[0] = 0; // Set indexes into string buffer to say not there... | |||||
dev->iStrings[1] = 0; | |||||
dev->iStrings[2] = 0; | |||||
dev->string_buf[0] = 0; // have trailing NULL.. | |||||
if (enumbuf[4] < 4 || enumbuf[5] != 3) { | if (enumbuf[4] < 4 || enumbuf[5] != 3) { | ||||
dev->enum_state = 11; | dev->enum_state = 11; | ||||
} else { | } else { | ||||
} | } | ||||
void USBHost::convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer) { | void USBHost::convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer) { | ||||
strbuf_t *strbuf = dev->strbuf; | |||||
if (!strbuf) return; // don't have a buffer | |||||
uint8_t *buffer = (uint8_t*)transfer->buffer; | uint8_t *buffer = (uint8_t*)transfer->buffer; | ||||
uint8_t buf_index = string_index? dev->iStrings[string_index]+1 : 0; | |||||
uint8_t buf_index = string_index? strbuf->iStrings[string_index]+1 : 0; | |||||
// Try to verify - The first byte should be length and the 2nd byte should be 0x3 | // Try to verify - The first byte should be length and the 2nd byte should be 0x3 | ||||
if (!buffer || (buffer[1] != 0x3)) { | if (!buffer || (buffer[1] != 0x3)) { | ||||
return; // No string so can simply return | return; // No string so can simply return | ||||
} | } | ||||
dev->iStrings[string_index] = buf_index; // remember our starting positio | |||||
strbuf->iStrings[string_index] = buf_index; // remember our starting positio | |||||
uint8_t count_bytes_returned = buffer[0]; | uint8_t count_bytes_returned = buffer[0]; | ||||
if ((buf_index + count_bytes_returned/2) >= DEVICE_STRUCT_STRING_BUF_SIZE) | if ((buf_index + count_bytes_returned/2) >= DEVICE_STRUCT_STRING_BUF_SIZE) | ||||
count_bytes_returned = (DEVICE_STRUCT_STRING_BUF_SIZE - buf_index) * 2; | count_bytes_returned = (DEVICE_STRUCT_STRING_BUF_SIZE - buf_index) * 2; | ||||
// Now copy into our storage buffer. | // Now copy into our storage buffer. | ||||
for (uint8_t i = 2; (i < count_bytes_returned) && (buf_index < (DEVICE_STRUCT_STRING_BUF_SIZE -1)); i += 2) { | for (uint8_t i = 2; (i < count_bytes_returned) && (buf_index < (DEVICE_STRUCT_STRING_BUF_SIZE -1)); i += 2) { | ||||
dev->string_buf[buf_index++] = buffer[i]; | |||||
strbuf->buffer[buf_index++] = buffer[i]; | |||||
} | } | ||||
dev->string_buf[buf_index] = 0; // null terminate. | |||||
strbuf->buffer[buf_index] = 0; // null terminate. | |||||
// Update other indexes to point to null character | // Update other indexes to point to null character | ||||
while (++string_index < 3) { | while (++string_index < 3) { | ||||
dev->iStrings[string_index] = buf_index; // point to trailing NULL character | |||||
strbuf->iStrings[string_index] = buf_index; // point to trailing NULL character | |||||
} | } | ||||
} | } | ||||
prev_dev->next = p->next; | prev_dev->next = p->next; | ||||
} | } | ||||
println("removed Device_t from devlist"); | println("removed Device_t from devlist"); | ||||
if (p->strbuf != nullptr ) { | |||||
free_string_buffer(p->strbuf); | |||||
} | |||||
free_Device(p); | free_Device(p); | ||||
break; | break; | ||||
} | } |
USBHub hub1(myusb); | USBHub hub1(myusb); | ||||
USBHub hub2(myusb); | USBHub hub2(myusb); | ||||
USBHub hub3(myusb); | USBHub hub3(myusb); | ||||
USBHub hub4(myusb); | |||||
KeyboardController keyboard1(myusb); | KeyboardController keyboard1(myusb); | ||||
KeyboardController keyboard2(myusb); | KeyboardController keyboard2(myusb); | ||||
KeyboardHIDExtrasController hidextras(myusb); | KeyboardHIDExtrasController hidextras(myusb); | ||||
MouseController mouse1(myusb); | MouseController mouse1(myusb); | ||||
JoystickController joystick1(myusb); | JoystickController joystick1(myusb); | ||||
USBDriver *drivers[] = {&hub1, &hub2, &hub3, &keyboard1, &keyboard2, &hid1, &hid2, &hid3, &hid4, &hid5}; | |||||
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[1])) | |||||
const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2","Hub3", "KB1", "KB2", "HID1", "HID2", "HID3", "HID4", "HID5" }; | |||||
USBDriver *drivers[] = {&hub1, &hub2, &hub3, &hub4, &keyboard1, &keyboard2, &hid1, &hid2, &hid3, &hid4, &hid5}; | |||||
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0])) | |||||
const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2", "Hub3", "Hub4" "KB1", "KB2", "HID1", "HID2", "HID3", "HID4", "HID5" }; | |||||
bool driver_active[CNT_DEVICES] = {false, false, false, false}; | bool driver_active[CNT_DEVICES] = {false, false, false, false}; | ||||
// Lets also look at HID Input devices | |||||
USBHIDInput *hiddrivers[] = {&mouse1, &joystick1}; | |||||
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) | |||||
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1"}; | |||||
bool hid_driver_active[CNT_DEVICES] = {false, false}; | |||||
void setup() | void setup() | ||||
{ | { | ||||
while (!Serial) ; // wait for Arduino Serial Monitor | while (!Serial) ; // wait for Arduino Serial Monitor | ||||
Serial.println("\n\nUSB Host Testing"); | Serial.println("\n\nUSB Host Testing"); | ||||
Serial.println(sizeof(USBHub), DEC); | |||||
myusb.begin(); | myusb.begin(); | ||||
keyboard1.attachPress(OnPress); | keyboard1.attachPress(OnPress); | ||||
keyboard2.attachPress(OnPress); | keyboard2.attachPress(OnPress); | ||||
} | } | ||||
} | } | ||||
for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) { | |||||
if (*hiddrivers[i] != hid_driver_active[i]) { | |||||
if (hid_driver_active[i]) { | |||||
Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]); | |||||
hid_driver_active[i] = false; | |||||
} else { | |||||
Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct()); | |||||
hid_driver_active[i] = true; | |||||
const uint8_t *psz = hiddrivers[i]->manufacturer(); | |||||
if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz); | |||||
psz = hiddrivers[i]->product(); | |||||
if (psz && *psz) Serial.printf(" product: %s\n", psz); | |||||
psz = hiddrivers[i]->serialNumber(); | |||||
if (psz && *psz) Serial.printf(" Serial: %s\n", psz); | |||||
} | |||||
} | |||||
} | |||||
if(mouse1.available()) { | if(mouse1.available()) { | ||||
Serial.print("Mouse: buttons = "); | Serial.print("Mouse: buttons = "); | ||||
Serial.print(mouse1.getButtons()); | Serial.print(mouse1.getButtons()); |
{ | { | ||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | ||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | ||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||||
driver_ready_for_device(this); | driver_ready_for_device(this); | ||||
} | } | ||||
contribute_Devices(mydevices, sizeof(mydevices)/sizeof(Device_t)); | contribute_Devices(mydevices, sizeof(mydevices)/sizeof(Device_t)); | ||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | ||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | ||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||||
driver_ready_for_device(this); | driver_ready_for_device(this); | ||||
} | } | ||||
{ | { | ||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | ||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | ||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||||
driver_ready_for_device(this); | driver_ready_for_device(this); | ||||
} | } | ||||
static Device_t * free_Device_list = NULL; | static Device_t * free_Device_list = NULL; | ||||
static Pipe_t * free_Pipe_list = NULL; | static Pipe_t * free_Pipe_list = NULL; | ||||
static Transfer_t * free_Transfer_list = NULL; | static Transfer_t * free_Transfer_list = NULL; | ||||
static strbuf_t * free_strbuf_list = NULL; | |||||
// A small amount of non-driver memory, just to get things started | // A small amount of non-driver memory, just to get things started | ||||
// TODO: is this really necessary? Can these be eliminated, so we | // TODO: is this really necessary? Can these be eliminated, so we | ||||
// use only memory from the drivers? | // use only memory from the drivers? | ||||
free_Transfer_list = transfer; | free_Transfer_list = transfer; | ||||
} | } | ||||
strbuf_t * USBHost::allocate_string_buffer(void) | |||||
{ | |||||
strbuf_t *strbuf = free_strbuf_list; | |||||
if (strbuf) { | |||||
free_strbuf_list = *(strbuf_t **)strbuf; | |||||
strbuf->iStrings[strbuf_t::STR_ID_MAN] = 0; // Set indexes into string buffer to say not there... | |||||
strbuf->iStrings[strbuf_t::STR_ID_PROD] = 0; | |||||
strbuf->iStrings[strbuf_t::STR_ID_SERIAL] = 0; | |||||
strbuf->buffer[0] = 0; // have trailing NULL.. | |||||
} | |||||
return strbuf; | |||||
} | |||||
void USBHost::free_string_buffer(strbuf_t *strbuf) | |||||
{ | |||||
*(strbuf_t **)strbuf = free_strbuf_list; | |||||
free_strbuf_list = strbuf; | |||||
} | |||||
void USBHost::contribute_Devices(Device_t *devices, uint32_t num) | void USBHost::contribute_Devices(Device_t *devices, uint32_t num) | ||||
{ | { | ||||
Device_t *end = devices + num; | Device_t *end = devices + num; | ||||
} | } | ||||
} | } | ||||
void USBHost::contribute_String_Buffers(strbuf_t *strbufs, uint32_t num) | |||||
{ | |||||
strbuf_t *end = strbufs + num; | |||||
for (strbuf_t *str = strbufs ; str < end; str++) { | |||||
free_string_buffer(str); | |||||
} | |||||
} | |||||
{ | { | ||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | ||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | ||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||||
handleNoteOff = NULL; | handleNoteOff = NULL; | ||||
handleNoteOn = NULL; | handleNoteOn = NULL; | ||||
handleVelocityChange = NULL; | handleVelocityChange = NULL; |
{ | { | ||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | ||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | ||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||||
driver_ready_for_device(this); | driver_ready_for_device(this); | ||||
} | } | ||||