Skip to content

Commit 16b67d8

Browse files
author
Loic Poulain
committed
usb: usbnet: ecm: Use transfer API
Replace low-level usb_read/usb_write with transfer functions. Signed-off-by: Loic Poulain <[email protected]>
1 parent 6c0c0ea commit 16b67d8

File tree

1 file changed

+77
-180
lines changed

1 file changed

+77
-180
lines changed

subsys/usb/class/netusb/function_ecm.c

Lines changed: 77 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@
2828
#define USB_CDC_ECM_REQ_TYPE 0x21
2929
#define USB_CDC_SET_ETH_PKT_FILTER 0x43
3030

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];
3632

3733
static int ecm_class_handler(struct usb_setup_packet *setup, s32_t *len,
3834
u8_t **data)
@@ -61,17 +57,16 @@ static void ecm_int_in(u8_t ep, enum usb_dc_ep_cb_status_code ep_status)
6157
SYS_LOG_DBG("EP 0x%x status %d", ep, ep_status);
6258
}
6359

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)
6662
{
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);
7065
u16_t ip_len;
7166

7267
if (len < NET_IPV6H_LEN + sizeof(struct net_eth_hdr)) {
73-
/* Too short to tell */
74-
return false;
68+
/* Too short */
69+
return 0;
7570
}
7671

7772
switch (ntohs(hdr->type)) {
@@ -84,201 +79,101 @@ static bool ecm_have_payload(struct net_pkt *pkt)
8479
break;
8580
default:
8681
SYS_LOG_DBG("Unknown hdr type 0x%04x", hdr->type);
87-
return false;
82+
return 0;
8883
}
8984

90-
return sizeof(struct net_eth_hdr) + ip_len <= len;
85+
return sizeof(struct net_eth_hdr) + ip_len;
9186
}
9287

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)
9589
{
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;
11092

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);
11794

118-
if (skip) {
119-
SYS_LOG_WRN("Skipping %u bytes", len);
95+
if (!pkt->frags) {
96+
return -ENODATA;
97+
}
12098

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);
124102

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;
129107
}
130108

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+
}
139116

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+
}
146119

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;
148124

149-
in_pkt = pkt;
125+
if (size <= 0) {
126+
goto done;
150127
}
151128

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.
157133
*/
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+
}
160139
}
161140

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;
168145
}
169146

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+
}
173153

174-
net_hexdump_frags(">", in_pkt);
154+
net_pkt_frag_insert(pkt, frag);
175155

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;
178160
}
179-
}
180161

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);
187163

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);
237167
}
238168

239-
static int ecm_send(struct net_pkt *pkt)
169+
static int ecm_connect(bool connected)
240170
{
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);
276173
} 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);
282177
}
283178

284179
return 0;
@@ -291,18 +186,20 @@ static struct usb_ep_cfg_data ecm_ep_data[] = {
291186
.ep_addr = CONFIG_CDC_ECM_INT_EP_ADDR
292187
},
293188
{
294-
.ep_cb = ecm_bulk_out,
189+
/* high-level transfer mgmt */
190+
.ep_cb = usb_transfer_ep_callback,
295191
.ep_addr = CONFIG_CDC_ECM_OUT_EP_ADDR
296192
},
297193
{
298-
.ep_cb = ecm_bulk_in,
194+
/* high-level transfer mgmt */
195+
.ep_cb = usb_transfer_ep_callback,
299196
.ep_addr = CONFIG_CDC_ECM_IN_EP_ADDR
300197
},
301198
};
302199

303200
struct netusb_function ecm_function = {
304201
.init = NULL,
305-
.connect_media = NULL,
202+
.connect_media = ecm_connect,
306203
.class_handler = ecm_class_handler,
307204
.send_pkt = ecm_send,
308205
.num_ep = ARRAY_SIZE(ecm_ep_data),

0 commit comments

Comments
 (0)