1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 by Tomasz Malesinski
11 * Copyright (C) 2008 by Maurus Cuelenaere
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
34 unsigned char *out_buf
;
37 void (*out_done
)(int, unsigned char *, int);
38 unsigned char out_in_progress
;
40 unsigned char *in_buf
;
44 void (*in_done
)(int, unsigned char *, int);
47 unsigned char halt
[2];
48 unsigned char enabled
[2];
49 short max_pkt_size
[2];
54 static unsigned char setup_pkt_buf
[8];
55 static struct usb_endpoint endpoints
[USB_NUM_ENDPOINTS
];
57 static bool high_speed_mode
= false;
59 static inline void or_int_value(volatile unsigned short *a
, volatile unsigned short *b
, unsigned long r
, unsigned long value
)
61 set_int_value(*a
, *b
, (r
| value
));
63 static inline void bc_int_value(volatile unsigned short *a
, volatile unsigned short *b
, unsigned long r
, unsigned long value
)
65 set_int_value(*a
, *b
, (r
& ~value
));
68 static inline void nop_f(void)
73 #define NOP asm volatile("nop\n");
75 static inline int ep_index(int n
, bool dir
)
77 return (n
<< 1) | dir
;
80 static inline bool epidx_dir(int idx
)
85 static inline int epidx_n(int idx
)
90 static inline void usb_select_endpoint(int idx
)
92 /* Select the endpoint */
93 ISP1583_DFLOW_EPINDEX
= idx
;
94 /* The delay time from the Write Endpoint Index register to the Read Data Port register must be at least 190 ns.
95 * The delay time from the Write Endpoint Index register to the Write Data Port register must be at least 100 ns.
100 static inline void usb_select_setup_endpoint(void)
102 /* Select the endpoint */
103 ISP1583_DFLOW_EPINDEX
= DFLOW_EPINDEX_EP0SETUP
;
104 /* The delay time from the Write Endpoint Index register to the Read Data Port register must be at least 190 ns.
105 * The delay time from the Write Endpoint Index register to the Write Data Port register must be at least 100 ns.
110 static void usb_setup_endpoint(int idx
, int max_pkt_size
, int type
)
112 if(epidx_n(idx
)!=EP_CONTROL
)
114 usb_select_endpoint(idx
);
115 ISP1583_DFLOW_MAXPKSZ
= max_pkt_size
& 0x7FF;
116 ISP1583_DFLOW_EPTYPE
= (DFLOW_EPTYPE_NOEMPKT
| DFLOW_EPTYPE_DBLBUF
| (type
& 0x3));
118 /* clear buffer ... */
119 ISP1583_DFLOW_CTRLFUN
|= DFLOW_CTRLFUN_CLBUF
;
120 /* ... twice because of double buffering */
121 usb_select_endpoint(idx
);
122 ISP1583_DFLOW_CTRLFUN
|= DFLOW_CTRLFUN_CLBUF
;
125 struct usb_endpoint
*ep
;
126 ep
= &(endpoints
[epidx_n(idx
)]);
127 ep
->halt
[epidx_dir(idx
)] = 0;
128 ep
->enabled
[epidx_dir(idx
)] = 0;
129 ep
->out_in_progress
= 0;
133 ep
->max_pkt_size
[epidx_dir(idx
)] = max_pkt_size
;
136 static void usb_enable_endpoint(int idx
)
138 if(epidx_n(idx
)!=EP_CONTROL
)
140 usb_select_endpoint(idx
);
141 /* Enable interrupt */
142 or_int_value(&ISP1583_INIT_INTEN_A
, &ISP1583_INIT_INTEN_B
, ISP1583_INIT_INTEN_READ
, 1 << (10 + idx
));
143 /* Enable endpoint */
144 ISP1583_DFLOW_EPTYPE
|= DFLOW_EPTYPE_ENABLE
;
147 endpoints
[epidx_n(idx
)].enabled
[epidx_dir(idx
)] = 1;
150 static void usb_disable_endpoint(int idx, bool set_struct)
152 usb_select_endpoint(idx);
153 ISP1583_DFLOW_EPTYPE &= ~DFLOW_EPTYPE_ENABLE;
154 bc_int_value(&ISP1583_INIT_INTEN_A, &ISP1583_INIT_INTEN_B, ISP1583_INIT_INTEN_READ, 1 << (10 + idx));
157 endpoints[epidx_n(idx)].enabled[epidx_dir(idx)] = 0;
160 static int usb_get_packet(unsigned char *buf
, int max_len
)
163 len
= ISP1583_DFLOW_BUFLEN
;
165 if (max_len
< 0 || max_len
> len
)
171 unsigned short d
= ISP1583_DFLOW_DATA
;
176 buf
[i
] = (d
>> 8) & 0xff;
182 static int usb_receive(int n
)
184 logf("usb_receive(%d)", n
);
187 if (endpoints
[n
].halt
[DIR_RX
]
188 || !endpoints
[n
].enabled
[DIR_RX
]
189 || endpoints
[n
].in_min_len
< 0
190 || !endpoints
[n
].in_ack
)
193 endpoints
[n
].in_ack
= 0;
195 usb_select_endpoint(ep_index(n
, DIR_RX
));
197 len
= usb_get_packet(endpoints
[n
].in_buf
+ endpoints
[n
].in_ptr
,
198 endpoints
[n
].in_max_len
- endpoints
[n
].in_ptr
);
199 endpoints
[n
].in_ptr
+= len
;
201 if (endpoints
[n
].in_ptr
>= endpoints
[n
].in_min_len
)
203 endpoints
[n
].in_min_len
= -1;
204 if (endpoints
[n
].in_done
)
205 (*(endpoints
[n
].in_done
))(n
, endpoints
[n
].in_buf
,
206 endpoints
[n
].in_ptr
);
212 static bool usb_out_buffer_full(int ep
)
214 usb_select_endpoint(ep_index(ep
, DIR_TX
));
215 if (ISP1583_DFLOW_EPTYPE
& 4) /* Check if type=bulk and double buffering is set */
216 return (ISP1583_DFLOW_BUFSTAT
& 3) == 3; /* Return true if both buffers are filled */
218 return (ISP1583_DFLOW_BUFSTAT
& 3) != 0; /* Return true if one of the buffers are filled */
221 static int usb_send(int n
)
223 logf("usb_send(%d)", n
);
224 int max_pkt_size
, len
;
228 if (endpoints
[n
].halt
[DIR_TX
]
229 || !endpoints
[n
].enabled
[DIR_TX
]
230 || !endpoints
[n
].out_in_progress
)
232 logf("NOT SEND TO EP!");
236 if (endpoints
[n
].out_ptr
< 0)
238 endpoints
[n
].out_in_progress
= 0;
239 if (endpoints
[n
].out_done
)
240 (*(endpoints
[n
].out_done
))(n
, endpoints
[n
].out_buf
,
241 endpoints
[n
].out_len
);
242 logf("ALREADY SENT TO EP!");
246 if (usb_out_buffer_full(n
))
248 logf("BUFFER FULL!");
252 usb_select_endpoint(ep_index(n
, DIR_TX
));
253 max_pkt_size
= endpoints
[n
].max_pkt_size
[DIR_TX
];
254 len
= endpoints
[n
].out_len
- endpoints
[n
].out_ptr
;
255 if (len
> max_pkt_size
)
258 if(len
< max_pkt_size
)
259 ISP1583_DFLOW_BUFLEN
= len
;
261 p
= endpoints
[n
].out_buf
+ endpoints
[n
].out_ptr
;
265 ISP1583_DFLOW_DATA
= p
[i
] | (p
[i
+ 1] << 8);
269 ISP1583_DFLOW_DATA
= p
[i
];
271 endpoints
[n
].out_ptr
+= len
;
274 if (endpoints[n].out_ptr == endpoints[n].out_len
275 && len < max_pkt_size)
277 if (endpoints
[n
].out_ptr
== endpoints
[n
].out_len
)
278 endpoints
[n
].out_ptr
= -1;
284 static void usb_stall_endpoint(int idx
)
286 usb_select_endpoint(idx
);
287 ISP1583_DFLOW_CTRLFUN
|= DFLOW_CTRLFUN_STALL
;
288 endpoints
[epidx_n(idx
)].halt
[epidx_dir(idx
)] = 1;
291 static void usb_unstall_endpoint(int idx
)
293 usb_select_endpoint(idx
);
294 ISP1583_DFLOW_CTRLFUN
&= ~DFLOW_CTRLFUN_STALL
;
295 ISP1583_DFLOW_EPTYPE
&= ~DFLOW_EPTYPE_ENABLE
;
296 ISP1583_DFLOW_EPTYPE
|= DFLOW_EPTYPE_ENABLE
;
297 ISP1583_DFLOW_CTRLFUN
|= DFLOW_CTRLFUN_CLBUF
;
298 if (epidx_dir(idx
) == DIR_TX
)
299 endpoints
[epidx_n(idx
)].out_in_progress
= 0;
302 endpoints
[epidx_n(idx
)].in_min_len
= -1;
303 endpoints
[epidx_n(idx
)].in_ack
= 0;
305 endpoints
[epidx_n(idx
)].halt
[epidx_dir(idx
)] = 0;
308 static void usb_status_ack(int ep
, int dir
)
310 logf("usb_status_ack(%d)", dir
);
312 usb_select_setup_endpoint();
314 usb_select_endpoint(ep_index(ep
, dir
));
316 ISP1583_DFLOW_CTRLFUN
|= DFLOW_CTRLFUN_STATUS
;
319 static void usb_data_stage_enable(int ep
, int dir
)
321 logf("usb_data_stage_enable(%d)", dir
);
322 usb_select_endpoint(ep_index(ep
, dir
));
323 ISP1583_DFLOW_CTRLFUN
|= DFLOW_CTRLFUN_DSEN
;
326 static void usb_handle_setup_rx(void)
329 usb_select_setup_endpoint();
330 len
= usb_get_packet(setup_pkt_buf
, 8);
334 ISP1583_DFLOW_CTRLFUN
|= DFLOW_CTRLFUN_STATUS
; /* Acknowledge packet */
335 usb_core_control_request((struct usb_ctrlrequest
*)setup_pkt_buf
);
339 usb_drv_stall(EP_CONTROL
, true, false);
340 usb_drv_stall(EP_CONTROL
, true, true);
341 logf("usb_handle_setup_rx() failed");
345 logf("usb_handle_setup_rx(): %02x %02x %02x %02x %02x %02x %02x %02x", setup_pkt_buf
[0], setup_pkt_buf
[1], setup_pkt_buf
[2], setup_pkt_buf
[3], setup_pkt_buf
[4], setup_pkt_buf
[5], setup_pkt_buf
[6], setup_pkt_buf
[7]);
348 static void usb_handle_data_int(int ep
, int dir
)
355 len
= usb_receive(ep
);
356 endpoints
[ep
].in_ack
= 1;
358 logf("usb_handle_data_int(%d, %d) finished", ep
, dir
);
361 bool usb_drv_powered(void)
364 return (ISP1583_INIT_OTG
& INIT_OTG_BSESS_VALID
) ? true : false;
366 return (ISP1583_INIT_MODE
& INIT_MODE_VBUSSTAT
) ? true : false;
370 static void setup_endpoints(void)
373 int max_pkt_size
= (high_speed_mode
? 512 : 64);
375 usb_setup_endpoint(ep_index(EP_CONTROL
, DIR_RX
), 64,
376 USB_ENDPOINT_XFER_CONTROL
);
377 usb_setup_endpoint(ep_index(EP_CONTROL
, DIR_TX
), 64,
378 USB_ENDPOINT_XFER_CONTROL
);
380 for(i
= 1; i
< USB_NUM_ENDPOINTS
-1; i
++)
382 usb_setup_endpoint(ep_index(i
, DIR_RX
), max_pkt_size
,
383 USB_ENDPOINT_XFER_BULK
);
384 usb_setup_endpoint(ep_index(i
, DIR_TX
), max_pkt_size
,
385 USB_ENDPOINT_XFER_BULK
);
388 usb_enable_endpoint(ep_index(EP_CONTROL
, DIR_RX
));
389 usb_enable_endpoint(ep_index(EP_CONTROL
, DIR_TX
));
391 for (i
= 1; i
< USB_NUM_ENDPOINTS
-1; i
++)
393 usb_enable_endpoint(ep_index(i
, DIR_RX
));
394 usb_enable_endpoint(ep_index(i
, DIR_TX
));
400 #if 0 /* currently unused */
401 static void usb_helper(void)
403 if(ISP1583_GEN_INT_READ
& ISP1583_INIT_INTEN_READ
)
405 logf("Helper detected interrupt... [%d]", (int)current_tick
);
411 void usb_drv_init(void)
413 /* Disable interrupt at CPU level */
416 /* Unlock the device's registers */
417 ISP1583_GEN_UNLCKDEV
= ISP1583_UNLOCK_CODE
;
419 /* Soft reset the device */
420 ISP1583_INIT_MODE
= INIT_MODE_SFRESET
;
422 /* Enable CLKAON & GLINTENA */
423 ISP1583_INIT_MODE
= STANDARD_INIT_MODE
;
425 /* Disable all OTG functions */
426 ISP1583_INIT_OTG
= 0;
429 logf("BUS_CONF/DA0:%d MODE0/DA1: %d MODE1: %d", (bool)(ISP1583_INIT_MODE
& INIT_MODE_TEST0
), (bool)(ISP1583_INIT_MODE
& INIT_MODE_TEST1
), (bool)(ISP1583_INIT_MODE
& INIT_MODE_TEST2
));
430 logf("Chip ID: 0x%x", ISP1583_GEN_CHIPID
);
431 //logf("INV0: 0x% IRQEDGE: 0x%x IRQPORT: 0x%x", IO_GIO_INV0, IO_GIO_IRQEDGE, IO_GIO_IRQPORT);
434 /*Set interrupt generation to target-specific mode +
435 * Set the control pipe to ACK only interrupt +
436 * Set the IN pipe to ACK only interrupt +
437 * Set OUT pipe to ACK and NYET interrupt
440 ISP1583_INIT_INTCONF
= 0x54 | INT_CONF_TARGET
;
441 /* Clear all interrupts */
442 set_int_value(ISP1583_GEN_INT_A
, ISP1583_GEN_INT_B
, 0xFFFFFFFF);
443 /* Enable USB interrupts */
444 set_int_value(ISP1583_INIT_INTEN_A
, ISP1583_INIT_INTEN_B
, STANDARD_INTEN
);
448 /* Enable interrupt at CPU level */
453 /* Clear device address and disable it */
454 ISP1583_INIT_ADDRESS
= 0;
456 /* Turn SoftConnect on */
457 ISP1583_INIT_MODE
|= INIT_MODE_SOFTCT
;
461 //tick_add_task(usb_helper);
463 logf("usb_init_device() finished");
466 int usb_drv_port_speed(void)
468 return (int)high_speed_mode
;
471 void usb_drv_exit(void)
473 logf("usb_drv_exit()");
476 ISP1583_INIT_MODE
&= ~INIT_MODE_SOFTCT
;
477 ISP1583_INIT_ADDRESS
= 0;
479 /* Disable interrupts */
480 set_int_value(ISP1583_INIT_INTEN_A
, ISP1583_INIT_INTEN_B
, 0);
481 /* and the CPU's one... */
485 /* Send usb controller to suspend mode */
486 ISP1583_INIT_MODE
= INIT_MODE_GOSUSP
;
487 ISP1583_INIT_MODE
= 0;
489 //tick_remove_task(usb_helper);
494 void usb_drv_stall(int endpoint
, bool stall
, bool in
)
496 logf("%sstall EP%d %s", (stall
? "" : "un"), endpoint
, (in
? "RX" : "TX" ));
498 usb_stall_endpoint(ep_index(endpoint
, (int)in
));
500 usb_unstall_endpoint(ep_index(endpoint
, (int)in
));
503 bool usb_drv_stalled(int endpoint
, bool in
)
505 return (endpoints
[endpoint
].halt
[(int)in
] == 1);
508 static void out_callback(int ep
, unsigned char *buf
, int len
)
511 logf("out_callback(%d, 0x%x, %d)", ep
, (int)buf
, len
);
512 usb_status_ack(ep
, DIR_RX
);
513 usb_core_transfer_complete(ep
, true, 0, len
); /* 0=>status succeeded, haven't worked out status failed yet... */
516 static void in_callback(int ep
, unsigned char *buf
, int len
)
519 logf("in_callback(%d, 0x%x, %d)", ep
, (int)buf
, len
);
520 usb_status_ack(ep
, DIR_TX
);
521 usb_core_transfer_complete(ep
, false, 0, len
);
524 int usb_drv_recv(int ep
, void* ptr
, int length
)
526 logf("usb_drv_recv(%d, 0x%x, %d)", ep
, (int)ptr
, length
);
527 if(ep
== EP_CONTROL
&& length
== 0 && ptr
== NULL
)
529 usb_status_ack(ep
, DIR_TX
);
532 endpoints
[ep
].in_done
= in_callback
;
533 endpoints
[ep
].in_buf
= ptr
;
534 endpoints
[ep
].in_max_len
= length
;
535 endpoints
[ep
].in_min_len
= length
;
536 endpoints
[ep
].in_ptr
= 0;
539 usb_data_stage_enable(ep
, DIR_RX
);
540 return usb_receive(ep
);
543 return usb_receive(ep
);
546 int usb_drv_send_nonblocking(int ep
, void* ptr
, int length
)
548 /* First implement DMA... */
549 return usb_drv_send(ep
, ptr
, length
);
552 static void usb_drv_wait(int ep
, bool send
)
554 logf("usb_drv_wait(%d, %d)", ep
, send
);
557 while (endpoints
[ep
].out_in_progress
)
562 while (endpoints
[ep
].in_ack
)
567 int usb_drv_send(int ep
, void* ptr
, int length
)
569 logf("usb_drv_send_nb(%d, 0x%x, %d)", ep
, (int)ptr
, length
);
570 if(ep
== EP_CONTROL
&& length
== 0 && ptr
== NULL
)
572 usb_status_ack(ep
, DIR_RX
);
575 if(endpoints
[ep
].out_in_progress
== 1)
577 endpoints
[ep
].out_done
= out_callback
;
578 endpoints
[ep
].out_buf
= ptr
;
579 endpoints
[ep
].out_len
= length
;
580 endpoints
[ep
].out_ptr
= 0;
581 endpoints
[ep
].out_in_progress
= 1;
584 int rc
= usb_send(ep
);
585 usb_data_stage_enable(ep
, DIR_TX
);
586 usb_drv_wait(ep
, DIR_TX
);
593 void usb_drv_reset_endpoint(int ep
, bool send
)
595 logf("reset endpoint(%d, %d)", ep
, send
);
596 usb_setup_endpoint(ep_index(ep
, (int)send
), endpoints
[ep
].max_pkt_size
[(int)send
], endpoints
[ep
].type
);
597 usb_enable_endpoint(ep_index(ep
, (int)send
));
600 void usb_drv_cancel_all_transfers(void)
602 logf("usb_drv_cancel_all_tranfers()");
605 for(i
=0;i
<USB_NUM_ENDPOINTS
-1;i
++)
606 endpoints
[i
].halt
[0] = endpoints
[i
].halt
[1] = 1;
609 int usb_drv_request_endpoint(int type
, int dir
)
613 if (type
!= USB_ENDPOINT_XFER_BULK
)
616 bit
=(dir
& USB_DIR_IN
)? 2:1;
618 for (i
=1; i
< USB_NUM_ENDPOINTS
; i
++) {
619 if((endpoints
[i
].allocation
& bit
)!=0)
621 endpoints
[i
].allocation
|= bit
;
628 void usb_drv_release_endpoint(int ep
)
630 int mask
= (ep
& USB_DIR_IN
)? ~2:~1;
631 endpoints
[ep
& 0x7f].allocation
&= mask
;
634 static void bus_reset(void)
636 /* Enable CLKAON & GLINTENA */
637 ISP1583_INIT_MODE
= STANDARD_INIT_MODE
;
638 /* Enable USB interrupts */
639 ISP1583_INIT_INTCONF
= 0x54 | INT_CONF_TARGET
;
640 set_int_value(ISP1583_INIT_INTEN_A
, ISP1583_INIT_INTEN_B
, STANDARD_INTEN
);
642 /* Disable all OTG functions */
643 ISP1583_INIT_OTG
= 0;
645 /* Clear device address and enable it */
646 ISP1583_INIT_ADDRESS
= INIT_ADDRESS_DEVEN
;
650 /* Reset endpoints to default */
653 logf("bus reset->done");
656 /* Method for handling interrupts, must be called from usb-<target>.c */
657 void IRAM_ATTR
usb_drv_int(void)
660 ints
= ISP1583_GEN_INT_READ
& ISP1583_INIT_INTEN_READ
;
665 /* Unlock the device's registers */
666 ISP1583_GEN_UNLCKDEV
= ISP1583_UNLOCK_CODE
;
668 //logf(" handling int [0x%lx & 0x%lx = 0x%x]", ISP1583_GEN_INT_READ, ISP1583_INIT_INTEN_READ, (int)ints);
670 if(ints
& INT_IEBRST
) /* Bus reset */
673 high_speed_mode
= false;
675 usb_core_bus_reset();
676 /* Mask bus reset interrupt */
677 set_int_value(ISP1583_GEN_INT_A
, ISP1583_GEN_INT_B
, INT_IEBRST
);
680 if(ints
& INT_IEP0SETUP
) /* EP0SETUP interrupt */
683 usb_handle_setup_rx();
685 if(ints
& INT_IEHS_STA
) /* change from full-speed to high-speed mode -> endpoints need to get reconfigured!! */
688 high_speed_mode
= true;
691 if(ints
& INT_EP_MASK
) /* Endpoints interrupt */
693 unsigned long ep_event
;
694 unsigned short i
= 10;
695 ep_event
= ints
& INT_EP_MASK
;
701 if(ep_event
& (1 << i
))
703 logf("EP%d %s interrupt", (i
- 10) / 2, i
% 2 ? "RX" : "TX");
704 usb_handle_data_int((i
- 10) / 2, i
% 2);
705 ep_event
&= ~(1 << i
);
710 if(ints
& INT_IERESM
&& !(ints
& INT_IESUSP
)) /* Resume status: status change from suspend to resume (active) */
714 if(ints
& INT_IESUSP
&& !(ints
& INT_IERESM
)) /* Suspend status: status change from active to suspend */
718 if(ints
& INT_IEDMA
) /* change in the DMA Interrupt Reason register */
722 if(ints
& INT_IEVBUS
) /* transition from LOW to HIGH on VBUS */
726 /* Mask all (enabled) interrupts */
727 set_int_value(ISP1583_GEN_INT_A
, ISP1583_GEN_INT_B
, ints
);
732 void usb_drv_set_address(int address
)
734 logf("usb_drv_set_address(0x%x)", address
);
735 ISP1583_INIT_ADDRESS
= (address
& 0x7F) | INIT_ADDRESS_DEVEN
;
740 void usb_drv_set_test_mode(int mode
)
742 logf("usb_drv_set_test_mode(%d)", mode
);
745 ISP1583_GEN_TSTMOD
= 0;
749 ISP1583_GEN_TSTMOD
= GEN_TSTMOD_JSTATE
;
752 ISP1583_GEN_TSTMOD
= GEN_TSTMOD_KSTATE
;
755 ISP1583_GEN_TSTMOD
= GEN_TSTMOD_SE0_NAK
;
758 //REG_PORTSC1 |= PORTSCX_PTC_PACKET;
761 //REG_PORTSC1 |= PORTSCX_PTC_FORCE_EN;
767 int dbg_usb_num_items(void)
769 return 2+USB_NUM_ENDPOINTS
*2;
772 const char* dbg_usb_item(int selected_item
, void *data
,
773 char *buffer
, size_t buffer_len
)
775 if(selected_item
< 2)
777 switch(selected_item
)
780 snprintf(buffer
, buffer_len
, "USB connected: %s", (usb_drv_connected() ? "Yes" : "No"));
783 snprintf(buffer
, buffer_len
, "HS mode: %s", (high_speed_mode
? "Yes" : "No"));
789 int n
= ep_index((selected_item
- 2) / 2, (selected_item
- 2) % 2);
790 if(endpoints
[n
].enabled
== false)
791 snprintf(buffer
, buffer_len
, "EP%d[%s]: DISABLED", epidx_n(n
), (epidx_dir(n
) ? "TX" : "RX"));
796 if(endpoints
[n
].out_in_progress
)
797 snprintf(buffer
, buffer_len
, "EP%d[TX]: TRANSFERRING DATA -> %d bytes/%d bytes", epidx_n(n
), (endpoints
[n
].out_len
- endpoints
[n
].out_ptr
), endpoints
[n
].out_len
);
799 snprintf(buffer
, buffer_len
, "EP%d[TX]: STANDBY", epidx_n(n
));
803 if(endpoints
[n
].in_buf
&& !endpoints
[n
].in_ack
)
804 snprintf(buffer
, buffer_len
, "EP%d[RX]: RECEIVING DATA -> %d bytes/%d bytes", epidx_n(n
), endpoints
[n
].in_ptr
, endpoints
[n
].in_max_len
);
806 snprintf(buffer
, buffer_len
, "EP%d[RX]: STANDBY", epidx_n(n
));