Files
retrobsd/sys/pic32/usb_function_cdc.c
Serge Vakulenko d1f1e614f0 Kernel sources reformated with 4 space indent, no tabs.
Unused file include/trace.h deleted.
2015-06-23 19:00:24 -07:00

285 lines
8.8 KiB
C

/*
* This file contains all of functions, macros, definitions, variables,
* datatypes, etc. that are required for usage with the CDC function
* driver. This file should be included in projects that use the CDC
* \function driver.
*
* The software supplied herewith by Microchip Technology Incorporated
* (the 'Company') for its PIC® Microcontroller is intended and
* supplied to you, the Company's customer, for use solely and
* exclusively on Microchip PIC Microcontroller products. The
* software is owned by the Company and/or its supplier, and is
* protected under applicable copyright laws. All rights are reserved.
* Any use in violation of the foregoing restrictions may subject the
* user to criminal sanctions under applicable laws, as well as to
* civil liability for the breach of the terms and conditions of this license.
*
* THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
* TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
* IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*/
#include <machine/pic32mx.h>
#include <machine/usb_device.h>
#include <machine/usb_function_cdc.h>
unsigned cdc_trf_state; // States are defined cdc.h
unsigned cdc_tx_len; // total tx length
LINE_CODING cdc_line_coding; // Buffer to store line coding information
static USB_HANDLE data_out;
static USB_HANDLE data_in;
static CONTROL_SIGNAL_BITMAP control_signal_bitmap;
static volatile unsigned char cdc_data_rx [CDC_DATA_OUT_EP_SIZE];
static volatile unsigned char cdc_data_tx [CDC_DATA_IN_EP_SIZE];
/*
* SEND_ENCAPSULATED_COMMAND and GET_ENCAPSULATED_RESPONSE are required
* requests according to the CDC specification.
* However, it is not really being used here, therefore a dummy buffer is
* used for conformance.
*/
#define DUMMY_LENGTH 0x08
static unsigned char dummy_encapsulated_cmd_response [DUMMY_LENGTH];
/*
* This routine checks the setup data packet to see if it
* knows how to handle it.
*/
void cdc_check_request()
{
/*
* If request recipient is not an interface then return
*/
if (usb_setup_pkt.Recipient != RCPT_INTF)
return;
/*
* If request type is not class-specific then return
*/
if (usb_setup_pkt.RequestType != CLASS)
return;
/*
* Interface ID must match interface numbers associated with
* CDC class, else return
*/
if (usb_setup_pkt.bIntfID != CDC_COMM_INTF_ID &&
usb_setup_pkt.bIntfID != CDC_DATA_INTF_ID)
return;
switch (usb_setup_pkt.bRequest)
{
case SEND_ENCAPSULATED_COMMAND:
// send the packet
usb_in_pipe[0].pSrc.bRam = (unsigned char*) &dummy_encapsulated_cmd_response;
usb_in_pipe[0].wCount = DUMMY_LENGTH;
usb_in_pipe[0].info.bits.ctrl_trf_mem = USB_INPIPES_RAM;
usb_in_pipe[0].info.bits.busy = 1;
break;
case GET_ENCAPSULATED_RESPONSE:
// Populate dummy_encapsulated_cmd_response first.
usb_in_pipe[0].pSrc.bRam = (unsigned char*) &dummy_encapsulated_cmd_response;
usb_in_pipe[0].info.bits.busy = 1;
break;
case SET_LINE_CODING:
usb_out_pipe[0].wCount = usb_setup_pkt.wLength;
usb_out_pipe[0].pDst.bRam = (unsigned char*) &cdc_line_coding._byte[0];
usb_out_pipe[0].pFunc = 0;
usb_out_pipe[0].info.bits.busy = 1;
break;
case GET_LINE_CODING:
usb_ep0_send_ram_ptr ((unsigned char*) &cdc_line_coding,
LINE_CODING_LENGTH, USB_EP0_INCLUDE_ZERO);
break;
case SET_CONTROL_LINE_STATE:
control_signal_bitmap._byte = (unsigned char)usb_setup_pkt.W_Value;
CONFIGURE_RTS(control_signal_bitmap.CARRIER_CONTROL);
CONFIGURE_DTR(control_signal_bitmap.DTE_PRESENT);
usb_in_pipe[0].info.bits.busy = 1;
break;
}
}
/*
* This function initializes the CDC function driver. This function sets
* the default line coding (baud rate, bit parity, number of data bits,
* and format). This function also enables the endpoints and prepares for
* the first transfer from the host.
*
* This function should be called after the SET_CONFIGURATION command.
* This is most simply done by calling this function from the
* usbcb_init_ep() function.
*
* Usage:
* void usbcb_init_ep()
* {
* cdc_init_ep();
* }
*/
void cdc_init_ep()
{
// Abstract line coding information
cdc_line_coding.dwDTERate = 115200; // baud rate
cdc_line_coding.bCharFormat = 0; // 1 stop bit
cdc_line_coding.bParityType = 0; // None
cdc_line_coding.bDataBits = 8; // 5,6,7,8, or 16
cdc_trf_state = CDC_TX_READY;
cdc_tx_len = 0;
/*
* Do not have to init Cnt of IN pipes here.
* Reason: Number of BYTEs to send to the host
* varies from one transaction to
* another. Cnt should equal the exact
* number of BYTEs to transmit for
* a given IN transaction.
* This number of BYTEs will only
* be known right before the data is
* sent.
*/
usb_enable_endpoint (CDC_COMM_EP, USB_IN_ENABLED |
USB_HANDSHAKE_ENABLED | USB_DISALLOW_SETUP);
usb_enable_endpoint (CDC_DATA_EP, USB_IN_ENABLED | USB_OUT_ENABLED |
USB_HANDSHAKE_ENABLED | USB_DISALLOW_SETUP);
data_out = usb_rx_one_packet (CDC_DATA_EP,
(unsigned char*) &cdc_data_rx, sizeof(cdc_data_rx));
data_in = 0;
}
/*
* Get received data.
*/
int cdc_consume (void (*func) (int))
{
unsigned len;
if (! data_out || usb_handle_busy (data_out))
return 0;
/*
* Pass received data to user function.
*/
len = usb_handle_get_length (data_out);
if (func != 0) {
unsigned n;
for (n=0; n<len; n++)
func (cdc_data_rx[n]);
}
/*
* Prepare dual-ram buffer for next OUT transaction
*/
data_out = usb_rx_one_packet (CDC_DATA_EP,
(unsigned char*) &cdc_data_rx, sizeof(cdc_data_rx));
return len;
}
/*
* Send a symbol to the USB.
* Return a number of free bytes in transmit buffer.
*
* Usage:
* if (cdc_is_tx_ready()) {
* do {
* space = cdc_putc (data[i++]);
* } while (space > 0);
* }
* Conditions:
* cdc_is_tx_ready() must return TRUE. This indicates that the last
* transfer is complete and is ready to receive a new block of data.
*/
int cdc_putc (int c)
{
if (cdc_trf_state != CDC_TX_READY || cdc_tx_len >= sizeof(cdc_data_tx))
return 0;
cdc_data_tx [cdc_tx_len++] = c;
return sizeof(cdc_data_tx) - cdc_tx_len;
}
/*
* cdc_tx_service handles device-to-host transaction(s). This function
* should be called once per Main Program loop after the device reaches
* the configured state.
*
* Usage:
* void main()
* {
* usb_device_init();
* while (1)
* {
* usb_device_tasks();
* if (USBGetDeviceState() < CONFIGURED_STATE || USBIsDeviceSuspended())
* {
* // Either the device is not configured or we are suspended
* // so we don't want to do execute any application code
* continue; // go back to the top of the while loop
* } else {
* // Keep trying to send data to the PC as required
* cdc_tx_service();
*
* // Run application code.
* UserApplication();
* }
* }
* }
*/
void cdc_tx_service()
{
// Check that USB connection is established.
if (usb_device_state < CONFIGURED_STATE ||
(U1PWRC & PIC32_U1PWRC_USUSPEND))
return;
if (usb_handle_busy(data_in))
return;
/*
* Completing stage is necessary while [ mCDCUSartTxIsBusy()==1 ].
* By having this stage, user can always check cdc_trf_state,
* and not having to call mCDCUsartTxIsBusy() directly.
*/
if (cdc_trf_state == CDC_TX_COMPLETING) {
cdc_trf_state = CDC_TX_READY;
cdc_tx_len = 0;
}
/*
* If CDC_TX_BUSY_ZLP state, send zero length packet
*/
if (cdc_trf_state == CDC_TX_BUSY_ZLP)
{
data_in = usb_tx_one_packet (CDC_DATA_EP, 0, 0);
cdc_trf_state = CDC_TX_COMPLETING;
return;
}
/*
* Send a next packet.
*/
if (cdc_trf_state == CDC_TX_READY && cdc_tx_len > 0) {
/*
* Determine if a zero length packet state is necessary.
* See explanation in USB Specification 2.0: Section 5.8.3
*/
if (cdc_tx_len == CDC_DATA_IN_EP_SIZE)
cdc_trf_state = CDC_TX_BUSY_ZLP;
else
cdc_trf_state = CDC_TX_COMPLETING;
data_in = usb_tx_one_packet (CDC_DATA_EP, (unsigned char*)&cdc_data_tx, cdc_tx_len);
}
}