📄 ncdevice.c
字号:
{ // Handle Setup Packet Interrupt
// Upon ACKing a Setup Packet, the NET2272 will:
// - Set Setup Packet Interrupt (which is how we got here)
// - Set EP0 Endpoint Direction to match bit 7 of bmRequestType
// - Set EP0 Endpoint Toggle (Toggle always set for first Data Phase packet)
// - Set EP0 Control Status Phase Handshake (must be cleared by firmware
// to allow the Status Phase to complete)
// - Clear EP0 Endpoint Halt (guarantees the Setup Request will be ACK'd)
// - Clear EP0 data buffers (resets pointers so buffers appear empty)
// See USB 2.0: 8.5.3 for details about setup packets and control transfers
// Setup to interrupt on the start of the Status Phase, which is:
// - OUT token for Control Read or "no-data" request (wLength is zero)
// - IN token for Control Write
NCSTATUS NcStatus;
NETCHIP_WRITE(IRQSTAT1, 1<<CONTROL_STATUS_INTERRUPT);
NETCHIP_WRITE(IRQENB1, NETCHIP_READ(IRQENB1) | (1<<CONTROL_STATUS_INTERRUPT_ENABLE));
// Ensure Control Read pre-validation setting is beyond maximum size
// - Control Writes can leave non-zero values in EP_TRANSFER. If
// an EP0 transfer following the Control Write is a Control Read,
// the NET2272 sees the non-zero EP_TRANSFER as an unexpected
// pre-validation count.
// - Setting EP_TRANSFER beyond the maximum EP0 transfer size ensures
// the pre-validation count cannot cause an unexpected validatation
NETCHIP_WRITE(PAGESEL, EP0);
NETCHIP_WRITE(EP_TRANSFER2, 0xff);
NETCHIP_WRITE(EP_TRANSFER1, 0xff);
NETCHIP_WRITE(EP_TRANSFER0, 0xff);
// Get a copy of the host's eight-byte Setup Packet
BMREQUESTTYPE = NETCHIP_READ(SETUP0);
BREQUEST = NETCHIP_READ(SETUP1);
WVALUE_LO = NETCHIP_READ(SETUP2);
WVALUE_HI = NETCHIP_READ(SETUP3);
WINDEX_LO = NETCHIP_READ(SETUP4);
WINDEX_HI = NETCHIP_READ(SETUP5);
WLENGTH_LO = NETCHIP_READ(SETUP6);
WLENGTH_HI = NETCHIP_READ(SETUP7);
HISTO(DEFAULT_HISTORY, "SPk1", BMREQUESTTYPE, BREQUEST, WVALUE);
HISTO(DEFAULT_HISTORY, "SPk2", WINDEX, WLENGTH, 0);
NCDEBUG(SetupPacket_Msg[0] = '\0';)
NCDEBUG(SetupPacket_PrintVolume = VOLUME_MEDIUM;)
// Allow another Setup Packet Interrupt
NETCHIP_WRITE(IRQSTAT0, 1<<SETUP_PACKET_INTERRUPT);
// Parse host's eight-byte setup request:
// - The client gets the first opportunity to handle the request. If
// the client returns Unsuccessful, the API calls its Standard USB Request
// handler. Endpoint Zero is stalled if the request is not handled by either.
// - Request handlers may optionally start a data phase for a control
// transfer (USB Spec: 8.5.3). The client (or the app) effectively (or
// literally) calls the API Endpoint Transfer routine to specify a transfer
// - The API uses Endpoint Zero's Default Transfer Object for the data
// phase of control transfers for standard requests. If the client also
// performs data phase transfers, it should specify a separate Transfer
// Object before starting an endpoint zero transfer
// - Standard requests are listed in USB Spec section 9.4
// - Non-standard requests are vendor or class specific requests. See USB
// spec 9.3.1 and class documents (www.usb.org)
PrivDeviceObject->EventCode = NC_DEVICE_EVENT_DEVICE_REQUEST;
NcStatus = PrivDeviceObject->DeviceEventHandler(PrivDeviceObject);
// Preserve client's Transfer Object between possible Standard Requests
// - The API's standard request handlers use private Transfer Objects, but
// the client's *reference* to its Transfer Object must be preserved!
// - Even if requests alternate between standard (handled by the API) and non-
// standard (handled by client) the client will not require extra considerations
ClientTransferZero = PrivDeviceObject->EndpointZero->Transfer;
HISTO(DEFAULT_HISTORY, "Clie", NcStatus, 0, 0);
if (NcStatus != NCSTATUS_SUCCESS)
{ // Anything other than Success indicates that the API should handle the request
// - Try API's standard request handler
// Switch Transfer Object to API's private transfer object
// Assert: The API's private object is never expected to be the same as the client's!
ASSERT(PhysicalEndpoints[EP0]->Transfer != &PrivateTransferZero);
PhysicalEndpoints[EP0]->Transfer = &PrivateTransferZero;
NcStatus = NCSTATUS_SUCCESS;
StandardUsbRequestHandler(&NcStatus);
}
if (NcStatus == NCSTATUS_UNSUCCESSFUL)
{ // Unable to fulfill host's request. The request may have been recognized (by the
// client or the API) but it still failed. More likely, however, is that the
// request was not recognized by either the client or the API
// - Stall endpoint zero
// - Return without starting a data or status phase
HISTO(VOLUME_MINIMUM, "SpS!", (BMREQUESTTYPE<<8) | (BREQUEST<<0), WVALUE, WINDEX);
NETCHIP_WRITE(PAGESEL, EP0);
NETCHIP_WRITE(EP_RSPSET, 1<<ENDPOINT_HALT);
NCPRINTF(VOLUME_MINIMUM, ("StandardUsbRequestHandler(): Stalled! Setup Packet:"
"%2.2x %2.2x %4.4x %4.4x %4.4x\n",
BMREQUESTTYPE,
BREQUEST,
WVALUE,
WINDEX,
WLENGTH
));
// Restore client's transfer object
PrivDeviceObject->EndpointZero->Transfer = ClientTransferZero;
return;
}
ASSERT(NcStatus == NCSTATUS_SUCCESS);
NCPRINTF(SetupPacket_PrintVolume,
("Request: %2.2x %2.2x %4.4x %4.4x %4.4x %s\n",
BMREQUESTTYPE,
BREQUEST,
WVALUE,
WINDEX,
WLENGTH,
SetupPacket_Msg
));
if (WLENGTH != 0)
{ // Host request includes a data phase
// - Set up transfer starting conditions (effectively like API's Endpoint Transfer routine)
LogicalEndpoints[EP0].Priv.pPkt = (PBYTE)LogicalEndpoints[EP0].Transfer->TransferBuffer;
LogicalEndpoints[EP0].Priv.BytesRemaining = LogicalEndpoints[EP0].Transfer->TransferSize;
LogicalEndpoints[EP0].CompletionStatus = NCSTATUS_PENDING;
}
// Start data phase:
// - Data phase routine handles data as well as no-data (i.e. wLength zero) cases
// - Status phase may be started if data phase completes (or if there is no data phase)
EpZero_DataPhase(PhysicalEndpoints[EP0]);
HISTO(DEFAULT_HISTORY, ")SPk", NETCHIP_READ(EP_IRQENB), NETCHIP_READ(EP_STAT0), NETCHIP_READ(EP_CFG));
}
///////////////////////////////////////////////////////////////////////////////
void
NcDev_UsbState(
PNC_DEVICE_OBJECT DeviceObject
)
{ // USB state (VBUS, reset, suspend, resume) handler
// - State machine to manage USB states (VBUS TRUE, VBUS FALSE, Suspend)
// - USB Power state is visible to client
// - Rules based on "Device State Diagram", See USB 2.0, figure 9-1
NCBYTE UsbCtl1 = NETCHIP_READ(USBCTL1);
NCBYTE IrqStat1 = NETCHIP_READ(IRQSTAT1);
HISTO(DEFAULT_HISTORY, "Stat", DeviceObject->UsbPowerState, UsbCtl1, IrqStat1);
NETCHIP_WRITE(IRQSTAT1, (
(1<<ROOT_PORT_RESET_INTERRUPT) |
(1<<RESUME_INTERRUPT) |
(1<<SUSPEND_REQUEST_CHANGE_INTERRUPT) |
(1<<VBUS_INTERRUPT) |
0));
// State machine for managing the USB State:
// - The state machine *must* change the event code if there is a
// change (It should assert if it doesn't!)
NCDEBUG(DeviceObject->EventCode = NC_DEVICE_EVENT_UNKNOWN);
if (!(UsbCtl1 & (1<<VBUS_PIN)))
{ // VBUS Pin FALSE (USB cable unplugged or host powered down):
NETCHIP_WRITE(IRQENB0, 0x00);
NETCHIP_WRITE(IRQENB1, USB_STATE_IRQENB1);
if (IrqStat1 & (1<<RESUME_INTERRUPT))
{ // Chip has awakened
// - Not changing state
DeviceObject->EventCode = NC_DEVICE_EVENT_CHIP_WAKEUP;
}
else if (DeviceObject->UsbPowerState == NC_USB_POWER_OFF)
{ // We are already in Power OFF state:
// - Not changing state, not calling client event handler
return;
}
else
{ // Change state due to VBUS pin
// - Going to Power OFF (due to VBUS Pin FALSE)
DeviceObject->UsbPowerState = NC_USB_POWER_OFF;
DeviceObject->EventCode = NC_DEVICE_EVENT_VBUS_FALSE;
}
}
else
{ // VBUS Pin is TRUE
// - Connected to USB host
switch(DeviceObject->UsbPowerState)
{
case NC_USB_POWER_OFF:
// VBUS Pin TRUE:
// - Going to Power ON (due to VBUS Pin TRUE)
DeviceObject->UsbPowerState = NC_USB_POWER_ON;
DeviceObject->EventCode = NC_DEVICE_EVENT_VBUS_TRUE;
break;
case NC_USB_POWER_ON:
if (IrqStat1 & (1<<SUSPEND_REQUEST_INTERRUPT))
{ // Suspend request:
// - Going to Suspend due to Suspend Request
// - Tip: To properly convey the state of the host, USB Power State
// goes to Suspend, even if the client chooses to NOT actually
// suspend the NET2272
// - Note: Unplugging USB cable slowly may cause a Suspend Request
// *before* VBUS goes FALSE. (This is due to the design of the pins
// in USB cables.) If the client decides to suspend the chip
// on such an unplug/suspend event, the NET2272 will NOT be
// aware that VBUS will soon go FALSE (since it's suspended). This
// means firmware may not accurately manage the USB Power State on
// an unplug. Possible remedies include external circuitry to determine
// the state of VBUS or perhaps wait for about 300mSec (in a non-interrupt
// context so that a VBUS FALSE interrupt has a chance to run), *then*
// suspend.
ASSERT(IrqStat1 & (1<<SUSPEND_REQUEST_CHANGE_INTERRUPT));
DeviceObject->UsbPowerState = NC_USB_POWER_SUSPEND;
DeviceObject->EventCode = NC_DEVICE_EVENT_SUSPEND;
break;
}
if ((IrqStat1 & ((1<<RESET_STATUS) | (1<<ROOT_PORT_RESET_INTERRUPT))) == (1<<ROOT_PORT_RESET_INTERRUPT))
{ // USB Reset ending (Reset Interrupt is TRUE, and Reset Status is FALSE)
// - A USB Reset does not change USB State
DeviceObject->EventCode = NC_DEVICE_EVENT_ROOT_PORT_RESET;
HISTO(DEFAULT_HISTORY, "Rst", 0, 0, NETCHIP_READ(IRQSTAT1));
break;
}
// Not changing state, not calling client event handler
NCPRINTF(VOLUME_MINIMUM, ("NcDev_UsbState() (POWER_ON): No event: IRQSTAT1:0x%2.2x USBCTL1:0x%2.2x\n",
IrqStat1,
UsbCtl1
));
return;
case NC_USB_POWER_SUSPEND:
// Coming out of suspend:
// - The chip may or may NOT have been asleep, but it's definitely awake
// now. Possible conditions:
// - Chip was suspended and awoke when the host resumed: Go to Resume state
// - Chip was not suspended when the host resumed: Go to Resume state
// - Chip was suspended and awoke, but NOT due to a host resume. Usually this
// happens when firmware accessed a chip register, but it can happen when
// there is some sort of noise on the USB signal lines: Chip wakeup event (State
// does NOT change.) Chip must be suspended with I/O Wakeup Enable TRUE
// for chip access to wake it
if ((IrqStat1 & ((1<<SUSPEND_REQUEST_CHANGE_INTERRUPT) | (1<<SUSPEND_REQUEST_INTERRUPT))) == (1<<SUSPEND_REQUEST_CHANGE_INTERRUPT))
{ // Resume (Suspend Request Change TRUE AND Suspend Request is FALSE):
// - Going to Power ON due to Resume
DeviceObject->EventCode = NC_DEVICE_EVENT_RESUME;
DeviceObject->UsbPowerState = NC_USB_POWER_ON;
break;
}
if ((IrqStat1 & ((1<<RESET_STATUS) | (1<<ROOT_PORT_RESET_INTERRUPT))) == (1<<ROOT_PORT_RESET_INTERRUPT))
{ // End of Reset (Reset Interrupt is TRUE AND Reset Status is FALSE):
// - Going to Power ON due to Reset
DeviceObject->EventCode = NC_DEVICE_EVENT_ROOT_PORT_RESET;
DeviceObject->UsbPowerState = NC_USB_POWER_ON;
break;
}
if (IrqStat1 & (1<<RESUME_INTERRUPT))
{ // Chip has awakened
// - State does NOT change
DeviceObject->EventCode = NC_DEVICE_EVENT_CHIP_WAKEUP;
break;
}
// Not changing state, not calling client
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -