28
28
#define USB_CDC_ECM_REQ_TYPE 0x21
29
29
#define USB_CDC_SET_ETH_PKT_FILTER 0x43
30
30
31
- /* Pointer to pkt assembling at the moment */
32
- static struct net_pkt * in_pkt ;
33
-
34
- /* In a case of low memory skip data to the end of the packet */
35
- static bool skip ;
31
+ static u8_t tx_buf [NETUSB_MTU ], rx_buf [NETUSB_MTU ];
36
32
37
33
static int ecm_class_handler (struct usb_setup_packet * setup , s32_t * len ,
38
34
u8_t * * data )
@@ -61,17 +57,16 @@ static void ecm_int_in(u8_t ep, enum usb_dc_ep_cb_status_code ep_status)
61
57
SYS_LOG_DBG ("EP 0x%x status %d" , ep , ep_status );
62
58
}
63
59
64
- /* Returns true if the given packet is long enough to hold the whole payload */
65
- static bool ecm_have_payload ( struct net_pkt * pkt )
60
+ /* Retrieve expected pkt size from ethernet/ip header */
61
+ static size_t ecm_eth_size ( void * ecm_pkt , size_t len )
66
62
{
67
- struct net_eth_hdr * hdr = NET_ETH_HDR (pkt );
68
- int len = net_pkt_get_len (pkt );
69
- u8_t * ip_data = pkt -> frags -> data + sizeof (struct net_eth_hdr );
63
+ struct net_eth_hdr * hdr = (void * )ecm_pkt ;
64
+ u8_t * ip_data = (u8_t * )ecm_pkt + sizeof (struct net_eth_hdr );
70
65
u16_t ip_len ;
71
66
72
67
if (len < NET_IPV6H_LEN + sizeof (struct net_eth_hdr )) {
73
- /* Too short to tell */
74
- return false ;
68
+ /* Too short */
69
+ return 0 ;
75
70
}
76
71
77
72
switch (ntohs (hdr -> type )) {
@@ -84,201 +79,101 @@ static bool ecm_have_payload(struct net_pkt *pkt)
84
79
break ;
85
80
default :
86
81
SYS_LOG_DBG ("Unknown hdr type 0x%04x" , hdr -> type );
87
- return false ;
82
+ return 0 ;
88
83
}
89
84
90
- return sizeof (struct net_eth_hdr ) + ip_len <= len ;
85
+ return sizeof (struct net_eth_hdr ) + ip_len ;
91
86
}
92
87
93
- /* Host to device data out */
94
- static void ecm_bulk_out (u8_t ep , enum usb_dc_ep_cb_status_code ep_status )
88
+ static int ecm_send (struct net_pkt * pkt )
95
89
{
96
- struct net_pkt * pkt ;
97
- struct net_buf * buf ;
98
- u8_t buffer [CONFIG_CDC_ECM_BULK_EP_MPS ];
99
- u32_t len ;
100
-
101
- usb_read (ep , NULL , 0 , & len );
102
- #if VERBOSE_DEBUG
103
- SYS_LOG_DBG ("EP 0x%x status %d len %u" , ep , ep_status , len );
104
- #endif
105
-
106
- if (unlikely (len > CONFIG_CDC_ECM_BULK_EP_MPS || !len )) {
107
- SYS_LOG_ERR ("Incorrect length: %u" , len );
108
- return ;
109
- }
90
+ struct net_buf * frag ;
91
+ int b_idx = 0 , ret ;
110
92
111
- /*
112
- * Quark SE USB controller is always storing data
113
- * in the FIFOs per 32-bit words. Now handled in the
114
- * usb_read().
115
- */
116
- usb_read (ep , buffer , len , NULL );
93
+ net_hexdump_frags ("<" , pkt );
117
94
118
- if (skip ) {
119
- SYS_LOG_WRN ("Skipping %u bytes" , len );
95
+ if (!pkt -> frags ) {
96
+ return - ENODATA ;
97
+ }
120
98
121
- if ( len < sizeof ( buffer )) {
122
- SYS_LOG_WRN ( "End skipping fragments" );
123
- skip = false ;
99
+ /* copy header */
100
+ memcpy ( & tx_buf [ b_idx ], net_pkt_ll ( pkt ), net_pkt_ll_reserve ( pkt ) );
101
+ b_idx += net_pkt_ll_reserve ( pkt ) ;
124
102
125
- return ;
126
- }
127
-
128
- return ;
103
+ /* copy payload */
104
+ for ( frag = pkt -> frags ; frag ; frag = frag -> frags ) {
105
+ memcpy ( & tx_buf [ b_idx ], frag -> data , frag -> len );
106
+ b_idx += frag -> len ;
129
107
}
130
108
131
- /* Start new packet */
132
- if (!in_pkt ) {
133
- pkt = net_pkt_get_reserve_rx (0 , K_NO_WAIT );
134
- if (!pkt ) {
135
- SYS_LOG_ERR ("Not enough memory for pkt buffer" );
136
- skip = true;
137
- return ;
138
- }
109
+ /* transfer data to host */
110
+ ret = usb_transfer_sync (CONFIG_CDC_ECM_IN_EP_ADDR , tx_buf , b_idx ,
111
+ USB_TRANS_WRITE );
112
+ if (ret != b_idx ) {
113
+ SYS_LOG_ERR ("Transfer failure" );
114
+ return - EINVAL ;
115
+ }
139
116
140
- buf = net_pkt_get_frag (pkt , K_NO_WAIT );
141
- if (!buf ) {
142
- net_pkt_unref (pkt );
143
- SYS_LOG_ERR ("Not enough memory for network buffers" );
144
- return ;
145
- }
117
+ return 0 ;
118
+ }
146
119
147
- net_pkt_frag_insert (pkt , buf );
120
+ static void ecm_read_cb (u8_t ep , int size , void * priv )
121
+ {
122
+ struct net_pkt * pkt ;
123
+ struct net_buf * frag ;
148
124
149
- in_pkt = pkt ;
125
+ if (size <= 0 ) {
126
+ goto done ;
150
127
}
151
128
152
- /* The ECM spec says that the end of a packet is marked by
153
- * a short frame. If the packet is a multiple of the endpoint
154
- * size then the host should send a zero length packet.
155
- * Linux, however, sends a one byte packet instead. Handle by
156
- * checking the IP header length and dropping the extra byte.
129
+ /* Linux considers by default that network usb device controllers are
130
+ * not able to handle Zero Lenght Packet (ZLP) and then generates
131
+ * a short packet containing a null byte. Handle by checking the IP
132
+ * header length and dropping the extra byte.
157
133
*/
158
- if (len == 1 && ecm_have_payload (in_pkt )) {
159
- len = 0 ;
134
+ if (rx_buf [size - 1 ] == 0 ) { /* last byte is null */
135
+ if (ecm_eth_size (rx_buf , size ) == (size - 1 )) {
136
+ /* last byte has been appended as delimiter, drop it */
137
+ size -- ;
138
+ }
160
139
}
161
140
162
- if (!net_pkt_append_all (in_pkt , len , buffer , K_FOREVER )) {
163
- SYS_LOG_ERR ("Error appending data to pkt: %p" , in_pkt );
164
-
165
- net_pkt_unref (in_pkt );
166
- in_pkt = NULL ;
167
- return ;
141
+ pkt = net_pkt_get_reserve_rx (0 , K_FOREVER );
142
+ if (!pkt ) {
143
+ SYS_LOG_ERR ("no memory for network packet\n" );
144
+ goto done ;
168
145
}
169
146
170
- if (len < sizeof (buffer )) {
171
- SYS_LOG_DBG ("ECM network packet received, len %u" ,
172
- net_pkt_get_len (in_pkt ));
147
+ frag = net_pkt_get_frag (pkt , K_FOREVER );
148
+ if (!frag ) {
149
+ SYS_LOG_ERR ("no memory for network packet\n" );
150
+ net_pkt_unref (pkt );
151
+ goto done ;
152
+ }
173
153
174
- net_hexdump_frags ( ">" , in_pkt );
154
+ net_pkt_frag_insert ( pkt , frag );
175
155
176
- netusb_recv (in_pkt );
177
- in_pkt = NULL ;
156
+ if (!net_pkt_append_all (pkt , size , rx_buf , K_FOREVER )) {
157
+ SYS_LOG_ERR ("no memory for network packet\n" );
158
+ net_pkt_unref (pkt );
159
+ goto done ;
178
160
}
179
- }
180
161
181
- static void ecm_bulk_in (u8_t ep , enum usb_dc_ep_cb_status_code ep_status )
182
- {
183
- #if VERBOSE_DEBUG
184
- SYS_LOG_DBG ("EP 0x%x status %d" , ep , ep_status );
185
- #endif
186
- }
162
+ netusb_recv (pkt );
187
163
188
- /*
189
- * The idea here is to use one buffer of size endpoint MPS (64 bytes)
190
- * for sending pkt without linearlizing first since we would need Ethernet
191
- * packet frame as a buffer up to 1518 bytes and it would require two
192
- * iterations.
193
- */
194
- static int append_bytes (u8_t * out_buf , u16_t buf_len , u8_t * data ,
195
- u16_t len , u16_t remaining )
196
- {
197
- int ret ;
198
-
199
- do {
200
- u16_t count = min (len , remaining );
201
- #if VERBOSE_DEBUG
202
- SYS_LOG_DBG ("len %u remaining %u count %u" , len , remaining ,
203
- count );
204
- #endif
205
-
206
- memcpy (out_buf + (buf_len - remaining ), data , count );
207
-
208
- data += count ;
209
- remaining -= count ;
210
- len -= count ;
211
-
212
- /* Buffer filled */
213
- if (remaining == 0 ) {
214
- #if VERBOSE_DEBUG
215
- net_hexdump ("fragment" , out_buf , buf_len );
216
- #endif
217
-
218
- ret = try_write (CONFIG_CDC_ECM_IN_EP_ADDR , out_buf ,
219
- buf_len );
220
- if (ret ) {
221
- SYS_LOG_ERR ("Error sending data" );
222
- return ret ;
223
- }
224
-
225
- /* Consumed full buffer */
226
- if (len == 0 ) {
227
- return buf_len ;
228
- }
229
-
230
- remaining = buf_len ;
231
- }
232
- } while (len );
233
- #if VERBOSE_DEBUG
234
- net_hexdump ("fragment" , out_buf , buf_len - remaining );
235
- #endif
236
- return remaining ;
164
+ done :
165
+ usb_transfer (CONFIG_CDC_ECM_OUT_EP_ADDR , rx_buf , sizeof (rx_buf ),
166
+ USB_TRANS_READ , ecm_read_cb , NULL );
237
167
}
238
168
239
- static int ecm_send ( struct net_pkt * pkt )
169
+ static int ecm_connect ( bool connected )
240
170
{
241
- u8_t send_buf [CONFIG_CDC_ECM_BULK_EP_MPS ];
242
- int remaining = sizeof (send_buf );
243
- struct net_buf * frag ;
244
-
245
- net_hexdump_frags ("<" , pkt );
246
-
247
- if (!pkt -> frags ) {
248
- return - ENODATA ;
249
- }
250
-
251
- remaining = append_bytes (send_buf , sizeof (send_buf ),
252
- net_pkt_ll (pkt ),
253
- net_pkt_ll_reserve (pkt ) +
254
- pkt -> frags -> len ,
255
- remaining );
256
- if (remaining < 0 ) {
257
- return remaining ;
258
- }
259
-
260
- for (frag = pkt -> frags -> frags ; frag ; frag = frag -> frags ) {
261
- #if VERBOSE_DEBUG
262
- SYS_LOG_DBG ("Fragment %p len %u, remaining %u" ,
263
- frag , frag -> len , remaining );
264
- #endif
265
- remaining = append_bytes (send_buf , sizeof (send_buf ),
266
- frag -> data , frag -> len ,
267
- remaining );
268
- if (remaining < 0 ) {
269
- return remaining ;
270
- }
271
- }
272
-
273
- if (remaining > 0 && remaining < sizeof (send_buf )) {
274
- return try_write (CONFIG_CDC_ECM_IN_EP_ADDR , send_buf ,
275
- sizeof (send_buf ) - remaining );
171
+ if (connected ) {
172
+ ecm_read_cb (CONFIG_CDC_ECM_OUT_EP_ADDR , 0 , NULL );
276
173
} else {
277
- u8_t zero [] = { 0x00 };
278
-
279
- SYS_LOG_DBG ("Send Zero packet to mark frame end" );
280
-
281
- return try_write (CONFIG_CDC_ECM_IN_EP_ADDR , zero , sizeof (zero ));
174
+ /* Cancel any transfer */
175
+ usb_cancel_transfer (CONFIG_CDC_ECM_OUT_EP_ADDR );
176
+ usb_cancel_transfer (CONFIG_CDC_ECM_IN_EP_ADDR );
282
177
}
283
178
284
179
return 0 ;
@@ -291,18 +186,20 @@ static struct usb_ep_cfg_data ecm_ep_data[] = {
291
186
.ep_addr = CONFIG_CDC_ECM_INT_EP_ADDR
292
187
},
293
188
{
294
- .ep_cb = ecm_bulk_out ,
189
+ /* high-level transfer mgmt */
190
+ .ep_cb = usb_transfer_ep_callback ,
295
191
.ep_addr = CONFIG_CDC_ECM_OUT_EP_ADDR
296
192
},
297
193
{
298
- .ep_cb = ecm_bulk_in ,
194
+ /* high-level transfer mgmt */
195
+ .ep_cb = usb_transfer_ep_callback ,
299
196
.ep_addr = CONFIG_CDC_ECM_IN_EP_ADDR
300
197
},
301
198
};
302
199
303
200
struct netusb_function ecm_function = {
304
201
.init = NULL ,
305
- .connect_media = NULL ,
202
+ .connect_media = ecm_connect ,
306
203
.class_handler = ecm_class_handler ,
307
204
.send_pkt = ecm_send ,
308
205
.num_ep = ARRAY_SIZE (ecm_ep_data ),
0 commit comments