void AT91F_CDC_Enumerate()

in src/cdc_enumerate.c [755:1055]


void AT91F_CDC_Enumerate() {
    uint8_t bmRequestType, bRequest, dir;
    uint16_t wValue, wIndex, wStatus;

    /* Clear the Received Setup flag */
    USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP;

    /* Read the USB request parameters */
    bmRequestType = ctrlOutCache.buf[0];
    bRequest = ctrlOutCache.buf[1];
    wValue = (ctrlOutCache.buf[2] & 0xFF);
    wValue |= (ctrlOutCache.buf[3] << 8);
    wIndex = (ctrlOutCache.buf[4] & 0xFF);
    wIndex |= (ctrlOutCache.buf[5] << 8);
    wLength = (ctrlOutCache.buf[6] & 0xFF);
    wLength |= (ctrlOutCache.buf[7] << 8);

    /* Clear the Bank 0 ready flag on Control OUT */
    USB->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY;

    uint32_t reqId = (bRequest << 8) | bmRequestType;

    logwrite("USBReq: ");
    logwritenum(reqId);
    logwrite(" wValue: ");
    logwritenum(wValue);
    logwrite(" wIndex: ");
    logwritenum(wIndex);
    logval(" wLen", wLength);

    /* Handle supported standard device request Cf Table 9-3 in USB
     * specification Rev 1.1 */
    switch (reqId) {
    case STD_GET_DESCRIPTOR1:
    case STD_GET_DESCRIPTOR:
        if (wValue == 0x100)
            /* Return Device Descriptor */
            sendCtrl(devDescriptor, sizeof(devDescriptor));
        else if (wValue == 0x200)
            /* Return Configuration Descriptor */
            sendCtrl(cfgDescriptor, sizeof(cfgDescriptor));
        else if (ctrlOutCache.buf[3] == 3) {
            if (ctrlOutCache.buf[2] >= STRING_DESCRIPTOR_COUNT)
            {
                stall_ep(0);
            } else {
                StringDescriptor desc = {0};
                desc.type = 3;
                if (ctrlOutCache.buf[2] == 0) {
                    desc.len = 4;
                    desc.data[0] = 0x09;
                    desc.data[1] = 0x04;
                } else {
                load_serial_number(serial_number);
                    const char *ptr = string_descriptors[ctrlOutCache.buf[2]];
                    desc.len = strlen(ptr) * 2 + 2;
                    for (int i = 0; ptr[i]; i++) {
                        desc.data[i * 2] = ptr[i];
                    }
                }
                sendCtrl(&desc, desc.len);
            }
        } else if (ctrlOutCache.buf[3] == 0x0F) {
            sendCtrl(bosDescriptor, sizeof(bosDescriptor));
        }
#if USE_HID
        else if (ctrlOutCache.buf[3] == 0x21) {
            sendCtrl(hidCfgDescriptor, sizeof(hidCfgDescriptor));
        } else if (ctrlOutCache.buf[3] == 0x22) {
            sendCtrl(hidDescriptor, sizeof(hidDescriptor));
        }
#endif
        else {
            /* Stall the request */
            stall_ep(0);
        }
        break;
#if USE_WEBUSB
    case STD_VENDOR_CTRL1:
        stall_ep(0);
        break;
    case STD_VENDOR_CTRL2:
        if (wIndex == 0x07)
            sendCtrl(msOS20Descriptor, sizeof(msOS20Descriptor));
        else
            stall_ep(0);
        break;
#endif
    case STD_SET_ADDRESS:
        /* Send ZLP */
        AT91F_USB_SendZlp();
        /* Set device address to the newly received address from host */
        USB->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | wValue;
        break;
    case STD_SET_CONFIGURATION:
        /* Store configuration */
        currentConfiguration = (uint8_t)wValue;
        /* Send ZLP */
        AT91F_USB_SendZlp();

#if USE_CDC
        configureInOut(USB_EP_IN);

        /* Configure INTERRUPT IN endpoint for CDC COMM interface*/
        USB->DEVICE.DeviceEndpoint[USB_EP_COMM].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4);
        /* Set maximum packet size as 64 bytes */
        usb_endpoint_table[USB_EP_COMM].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0;
        USB->DEVICE.DeviceEndpoint[USB_EP_COMM].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY;
#endif

        configureInOut(USB_EP_MSC_IN);

#if USE_HID
        /* Configure INTERRUPT IN/OUT endpoint for HID interface*/
        USB->DEVICE.DeviceEndpoint[USB_EP_HID].EPCFG.reg =
            USB_DEVICE_EPCFG_EPTYPE0(4) | USB_DEVICE_EPCFG_EPTYPE1(4);

        USB->DEVICE.DeviceEndpoint[USB_EP_HID].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_BK0RDY;
        USB->DEVICE.DeviceEndpoint[USB_EP_HID].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY;
        usb_endpoint_table[USB_EP_HID].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3;
        usb_endpoint_table[USB_EP_HID].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3;
#endif

#if USE_WEBUSB
        /* Configure INTERRUPT IN/OUT endpoint for HID interface*/
        USB->DEVICE.DeviceEndpoint[USB_EP_WEB].EPCFG.reg =
            USB_DEVICE_EPCFG_EPTYPE0(4) | USB_DEVICE_EPCFG_EPTYPE1(4);

        USB->DEVICE.DeviceEndpoint[USB_EP_WEB].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_BK0RDY;
        USB->DEVICE.DeviceEndpoint[USB_EP_WEB].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY;
        usb_endpoint_table[USB_EP_WEB].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3;
        usb_endpoint_table[USB_EP_WEB].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3;
#endif

        break;

    case STD_GET_CONFIGURATION:
        /* Return current configuration value */
        sendCtrl(&(currentConfiguration), sizeof(currentConfiguration));
        break;

    case STD_GET_STATUS_ZERO:
        wStatus = 0;
        sendCtrl(&wStatus, sizeof(wStatus));
        break;
    case STD_GET_STATUS_INTERFACE:
        wStatus = 0;
        sendCtrl(&wStatus, sizeof(wStatus));
        break;
    case STD_GET_STATUS_ENDPOINT:
        wStatus = 0;
        dir = wIndex & 80;
        wIndex &= 0x0F;
        if (wIndex < MAX_EP) {
            if (dir) {
                wStatus = (USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg &
                           USB_DEVICE_EPSTATUSSET_STALLRQ1)
                              ? 1
                              : 0;
            } else {
                wStatus = (USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg &
                           USB_DEVICE_EPSTATUSSET_STALLRQ0)
                              ? 1
                              : 0;
            }
            /* Return current status of endpoint */
            sendCtrl(&wStatus, sizeof(wStatus));
        } else
            /* Stall the request */
            stall_ep(0);
        break;
    case STD_SET_FEATURE_ZERO:
        /* Stall the request */
        stall_ep(0);
        break;
    case STD_SET_FEATURE_INTERFACE:
        /* Send ZLP */
        AT91F_USB_SendZlp();
        break;
    case STD_SET_FEATURE_ENDPOINT:
        dir = wIndex & 0x80;
        wIndex &= 0x0F;
        if ((wValue == 0) && wIndex && (wIndex < MAX_EP)) {
            /* Set STALL request for the endpoint */
            if (dir) {
                USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg =
                    USB_DEVICE_EPSTATUSSET_STALLRQ1;
            } else {
                USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg =
                    USB_DEVICE_EPSTATUSSET_STALLRQ0;
            }
            /* Send ZLP */
            AT91F_USB_SendZlp();
        } else
            /* Stall the request */
            stall_ep(0);
        break;
    case STD_CLEAR_FEATURE_ZERO:
        /* Stall the request */
        stall_ep(0);
        break;
    case STD_CLEAR_FEATURE_INTERFACE:
        /* Send ZLP */
        AT91F_USB_SendZlp();
        break;
    case STD_CLEAR_FEATURE_ENDPOINT:
        dir = wIndex & 0x80;
        wIndex &= 0x0F;
        if ((wValue == 0) && wIndex && (wIndex < MAX_EP)) {
            if (dir) {
                if (USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg &
                    USB_DEVICE_EPSTATUSSET_STALLRQ1) {
                    // Remove stall request
                    USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg =
                        USB_DEVICE_EPSTATUSCLR_STALLRQ1;
                    if (USB->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.reg &
                        USB_DEVICE_EPINTFLAG_STALL1) {
                        USB->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.reg =
                            USB_DEVICE_EPINTFLAG_STALL1;
                        // The Stall has occurred, then reset data toggle
                        USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg =
                            USB_DEVICE_EPSTATUSSET_DTGLIN;
                    }
                }
            } else {
                if (USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg &
                    USB_DEVICE_EPSTATUSSET_STALLRQ0) {
                    // Remove stall request
                    USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg =
                        USB_DEVICE_EPSTATUSCLR_STALLRQ0;
                    if (USB->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.reg &
                        USB_DEVICE_EPINTFLAG_STALL0) {
                        USB->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.reg =
                            USB_DEVICE_EPINTFLAG_STALL0;
                        // The Stall has occurred, then reset data toggle
                        USB->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg =
                            USB_DEVICE_EPSTATUSSET_DTGLOUT;
                    }
                }
            }
            /* Send ZLP */
            AT91F_USB_SendZlp();
        } else {
            stall_ep(0);
        }
        break;

#if USE_CDC
    // handle CDC class requests
    case SET_LINE_CODING:
        /* Send ZLP */
        AT91F_USB_SendZlp();
        break;
    case GET_LINE_CODING:
        /* Send current line coding */
        sendCtrl(&line_coding, sizeof(usb_cdc_line_coding_t));
        break;
    case SET_CONTROL_LINE_STATE:
        /* Store the current connection */
        pCdc.currentConnection = wValue;
        /* Send ZLP */
        AT91F_USB_SendZlp();
        break;
#endif

#if USE_MSC_CHECKS
    // MSC
    case MSC_RESET:
        DBG_MSC(logmsg("MSC reset"));
        msc_reset();
        break;
#endif

    case MSC_GET_MAX_LUN:
        DBG_MSC(logmsg("MSC maxlun"));
        wStatus = MAX_LUN;
        sendCtrl(&wStatus, 1);
        break;

#if USE_HID
    case HID_REQUEST_GET_PROTOCOL:
    case HID_REQUEST_GET_IDLE:
    case HID_REQUEST_GET_REPORT: {
        uint8_t buf[8] = {0};
        sendCtrl(buf, 8);
    } break;

    case HID_REQUEST_SET_IDLE:
    case HID_REQUEST_SET_REPORT:
    case HID_REQUEST_SET_PROTOCOL:
        AT91F_USB_SendZlp();
        break;
#endif

    default:
        logval("Invalid CTRL command", reqId);
        /* Stall the request */
        stall_ep(0);
        break;
    }
}