Search This Blog

Apr 17, 2013

Three VCPs support



Jussipo has made USB split mode enabled and dual VCP work on his side. So I started looking into this issue, fixed two defects and make three VCPs work. Here is the summary.
1.     Enable USB split mode
In src\LUFA\Drivers\USB\Core\SIM3u\Endpoint_SIM3U.c
...        ...        @@ -54,15 +54,15 @@ bool Endpoint_ConfigureEndpoint(const uint8_t Address,
54        54        
55        55                 if(Number != ENDPOINT_CONTROLEP)
56        56                 {
57                -                ep_config = 0x450024; // bit 2,5,16,18,22 must be writen
58                -
57        +                ep_config = 0x450424;  // bit 2,5,10,16,18,22 must be written
58        +                                       //IURF,ISTSTLI,SPLITEN, OPRDYI,OORF,OSTSTLI
59        59                         if(Type == EP_TYPE_ISOCHRONOUS)
60        60                         {   // ISO transfer need set "1"
61        61                                 ep_config |= (SI32_USBEP_A_EPCONTROL_IISOEN_ISO_U32);
62        62                         }
63        63                         if(dir_sel)
64        64                         {   // IN endpoint
65                -                        ep_config |= (SI32_USBEP_A_EPCONTROL_DIRSEL_IN_U32|SI32_USBEP_A_EPCONTROL_ICLRDT_RESET_U32);
65        +            ep_config |= (SI32_USBEP_A_EPCONTROL_ICLRDT_RESET_U32);
66        66                                 SI32_USBEP_A_set_in_max_packet_size(USB_EPn(Number),Size>>3);
67        67                         }
68        68                         else

2.     Make a function to sent endpoint direction.
In src\LUFA\Drivers\USB\Core\SIM3u\Endpoint_SIM3U.h
...        ...        @@ -591,7 +591,11 @@
591        591                                 static inline void Endpoint_SetEndpointDirection(const uint32_t DirectionMask) ATTR_ALWAYS_INLINE;
592        592                                 static inline void Endpoint_SetEndpointDirection(const uint32_t DirectionMask)
593        593                                 {
594                -                                return;
594        +                if( DirectionMask == ENDPOINT_DIR_IN)
595        +                    USB_EPn(usb_ep_selected)->EPCONTROL.DIRSEL = 1;
596        +                else
597        +                    USB_EPn(usb_ep_selected)->EPCONTROL.DIRSEL = 0;
598        +                return;
595        599                                 }
3.  Add Endpoint_SetEndpointDirection() call in CDC send/receive function

In src\LUFA\Drivers\USB\Class\Devcie\CDCClassDevice.c
old        new        
...        ...        @@ -160,6 +160,7 @@ uint8_t CDC_Device_SendData(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
160        160                 if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
161        161                   return ENDPOINT_RWSTREAM_DeviceDisconnected;
162        162        
163        +        Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
163        164                 Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address);
164        165                 return Endpoint_Write_Stream_LE(Buffer, Length, NULL);
165        166         }
...        ...        @@ -249,6 +250,7 @@ int16_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInf
249        250        
250        251                 int16_t ReceivedByte = -1;
251        252        
253        +        Endpoint_SetEndpointDirection(ENDPOINT_DIR_OUT);
252        254                 Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpoint.Address);
253        255        
254        256                 if (Endpoint_IsOUTReceived())
4.  Prepared three individual INF files for one, two, three VCPs
Main modifications are list below.
In src\VirtualSerial\
88        +[DeviceList]
89        +%DESCRIPTION%= DriverInstall,USB\VID_10C4&PID_A012&MI_00, USB\VID_10C4&PID_A012&MI_02
90        +
91        +[DeviceList.NTamd64]
92        +%DESCRIPTION%= DriverInstall,USB\VID_10C4&PID_A012&MI_00, USB\VID_10C4&PID_A012&MI_02

5.  Three VCP share same interrupt endpoint, and each BULK in/out endpoint number is same since we use USB split mode.
In src\VirtualSerial\Descriptors.h
...        ...        @@ -40,15 +40,33 @@
40        40                         #include
41        41        
42        42                 /* Macros: */
43        +        #define DUAL_VCP_ENABLE 1
44        +        #define TRI_VCP_ENABLE  0
45        +
43        46                         /** Endpoint address of the CDC device-to-host notification IN endpoint. */
44        47                         #define CDC_NOTIFICATION_EPADDR        (ENDPOINT_DIR_IN  | 1)
45        48        
46                -                /** Endpoint address of the CDC device-to-host data IN endpoint. */
47                -                #define CDC_TX_EPADDR                  (ENDPOINT_DIR_IN  | 2)
49        +        /** Endpoint address of the CDC1 device-to-host data IN endpoint. */
50        +                #define CDC1_TX_EPADDR                  (ENDPOINT_DIR_IN  | 2)
51        +
52        +                /** Endpoint address of the CDC1 host-to-device data OUT endpoint. */
53        +                #define CDC1_RX_EPADDR                  (ENDPOINT_DIR_OUT | 2)
54        +
55        +#if (DUAL_VCP_ENABLE || TRI_VCP_ENABLE)
56        +        /** Endpoint address of the CDC2 device-to-host data IN endpoint. */
57        +        #define CDC2_TX_EPADDR                  (ENDPOINT_DIR_IN  | 3)
58        +
59        +        /** Endpoint address of the CDC2 host-to-device data OUT endpoint. */
60        +        #define CDC2_RX_EPADDR                  (ENDPOINT_DIR_OUT | 3)
61        +#endif
48        62        
49                -                /** Endpoint address of the CDC host-to-device data OUT endpoint. */
50                -                #define CDC_RX_EPADDR                  (ENDPOINT_DIR_OUT | 3)
63        +#if (TRI_VCP_ENABLE)
64        +        /** Endpoint address of the CDC3 device-to-host data IN endpoint. */
65        +        #define CDC3_TX_EPADDR                  (ENDPOINT_DIR_IN  | 4)
51        66        
67        +        /** Endpoint address of the CDC3 host-to-device data OUT endpoint. */
68        +        #define CDC3_RX_EPADDR                  (ENDPOINT_DIR_OUT | 4)
69        +#endif

6.  Add IAD, second and third VCP descriptions.
In src\VirtualSerial\Descriptors.c
Here are part of modifications.
old        new        
...        ...        @@ -47,15 +47,21 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
47        47         {
48        48                 .Header                 = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
49        49        
50                -        .USBSpecification       = VERSION_BCD(01.10),
51                -        .Class                  = CDC_CSCP_CDCClass,
52                -        .SubClass               = CDC_CSCP_NoSpecificSubclass,
53                -        .Protocol               = CDC_CSCP_NoSpecificProtocol,
50        +    .USBSpecification       = VERSION_BCD(02.00),
51        +    .Class                  = USB_CSCP_IADDeviceClass,
52        +    .SubClass               = USB_CSCP_IADDeviceSubclass,
53        +    .Protocol               = USB_CSCP_IADDeviceProtocol,
54        54        
7.  Made other VCP works in main loop.
In src\VirtualSerial\VirtualSerial.c
87        150        
88        151         void VCOM_echo(void)
89        152         {
90                -        if(CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface))
153        +        if(CDC_Device_BytesReceived(&VirtualSerial_CDC1_Interface))
91        154                 {
92                -                in_buff[0] = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
93                -                CDC_Device_SendData(&VirtualSerial_CDC_Interface, (char *)in_buff, 1);
155        +                in_buff[0] = CDC_Device_ReceiveByte(&VirtualSerial_CDC1_Interface);
156        +                CDC_Device_SendData(&VirtualSerial_CDC1_Interface, (char *)in_buff, 1);
94        157                         Endpoint_ClearIN();
95        158                 }
159        +#if (DUAL_VCP_ENABLE || TRI_VCP_ENABLE)
160        +        if(CDC_Device_BytesReceived(&VirtualSerial_CDC2_Interface))
161        +        {
162        +                in2_buff[0] = CDC_Device_ReceiveByte(&VirtualSerial_CDC2_Interface);
163        +                CDC_Device_SendData(&VirtualSerial_CDC2_Interface, (char *)in2_buff, 1);
164        +                Endpoint_ClearIN();
165        +        }
166        +#endif
167        +#if (TRI_VCP_ENABLE)
168        +    if(CDC_Device_BytesReceived(&VirtualSerial_CDC3_Interface))
169        +    {
170        +        in3_buff[0] = CDC_Device_ReceiveByte(&VirtualSerial_CDC3_Interface);
171        +        CDC_Device_SendData(&VirtualSerial_CDC3_Interface, (char *)in3_buff, 1);
172        +        Endpoint_ClearIN();
173        +    }
174        +#endif
96        175         }

8.  Fix defect on handling zero package issue.
In src\LUFA\Drivers\USB\Core\SIM3u\EndpointStream_SIM3U.c
...        ...        @@ -265,6 +265,13 @@ uint8_t Endpoint_Write_Stream_LE(const void* const Buffer,
265        265                                 {
266        266                                         count = USB0_EP0_write_fifo(buf, Length);
267        267                                 }
268        +                        if(Length == ENDPOINT_CONTROLEP_DEFAULT_SIZE)
269        +                        {
270        +                                SI32_USB_A_set_in_packet_ready_ep0(SI32_USB_0);
271        +                                if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError)
272        +                                  return ErrorCode;
273        +                                SI32_USB_A_set_in_packet_ready_ep0(SI32_USB_0);
274        +                        }
9.  Fixed usb_ep_selected defect in USB ISR.
In src\LUFA\Drivers\USB\Core\SIM3u\USBInterrupt_SIM3U.c
...        ...        @@ -103,7 +103,7 @@ void USB0_IRQHandler(void)
103        103                   USB0_ep0_handler();
104        104                   return;
105        105           }
106                -
106        +  uint32_t ep_selected_backup = usb_ep_selected;
107        107           if (usbEpInterruptMask & (SI32_USB_A_IOINT_IN1I_MASK | SI32_USB_A_IOINT_OUT1I_MASK))
108        108           {
109        109                   Endpoint_SelectEndpoint(1);
...        ...        @@ -124,7 +124,7 @@ void USB0_IRQHandler(void)
124        124                   Endpoint_SelectEndpoint(4);
125        125                   USB0_epn_handler();
126        126           }
127                -
127        +  usb_ep_selected = ep_selected_backup;
128        128           // Handle Start of Frame Interrupt
10.          Source code

No comments: