1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "cdcecm.h"
17#include <unistd.h>
18#include "device_resource_if.h"
19#include "hdf_base.h"
20#include "hdf_device_object.h"
21#include "hdf_log.h"
22#include "osal_mem.h"
23#include "osal_sem.h"
24#include "osal_time.h"
25#include "securec.h"
26#include "usbfn_device.h"
27#include "usbfn_interface.h"
28#include "usbfn_request.h"
29
30#define HDF_LOG_TAG cdc_ecm
31#define UDC_NAME "invalid_udc_name"
32
33#define QUEUE_SIZE           8
34#define WRITE_BUF_SIZE       8192
35#define READ_BUF_SIZE        8192
36#define ECM_STATUS_BYTECOUNT 16
37#define ECM_BIT              9728000
38#define USBCDC_LEN 2
39#define RECEIVE_ALL_EVENTS 0xff
40static const int32_t WAIT_UDC_MAX_LOOP = 3;
41static const uint32_t WAIT_UDC_TIME = 100000;
42
43static int32_t EcmInit(struct HdfDeviceObject *device);
44static int32_t EcmRelease(struct HdfDeviceObject *device);
45
46static inline unsigned EcmBitrate(void)
47{
48    return ECM_BIT;
49}
50
51/* Usb Serial Related Functions */
52static int32_t UsbEcmStartTx(struct UsbEcm *port)
53{
54    struct DListHead *pool = &port->writePool;
55    if (port->ecm == NULL) {
56        return HDF_SUCCESS;
57    }
58
59    while (!port->writeBusy && !DListIsEmpty(pool)) {
60        struct UsbFnRequest *req = NULL;
61        uint32_t len;
62        if (port->writeStarted >= QUEUE_SIZE) {
63            break;
64        }
65        req = DLIST_FIRST_ENTRY(pool, struct UsbFnRequest, list);
66        OsalMutexLock(&port->lockWriteFifo);
67        len = DataFifoRead(&port->writeFifo, req->buf, port->ecm->dataInPipe.maxPacketSize);
68        OsalMutexUnlock(&port->lockWriteFifo);
69        if (len == 0) {
70            break;
71        }
72        req->length = len;
73        DListRemove(&req->list);
74        port->writeBusy = true;
75        int32_t ret = UsbFnSubmitRequestAsync(req);
76        port->writeBusy = false;
77        if (ret != HDF_SUCCESS) {
78            HDF_LOGE("%{public}s: send request error %{public}d", __func__, ret);
79            DListInsertTail(&req->list, pool);
80            break;
81        }
82        port->writeStarted++;
83        /* if ecm is disconnect, abort immediately */
84        if (port->ecm == NULL) {
85            break;
86        }
87    }
88    return HDF_SUCCESS;
89}
90
91static uint32_t UsbEcmStartRx(struct UsbEcm *port)
92{
93    struct DListHead *pool = &port->readPool;
94    struct UsbEcmPipe *out = &port->ecm->dataOutPipe;
95
96    while (!DListIsEmpty(pool)) {
97        struct UsbFnRequest *req = NULL;
98        int32_t ret;
99
100        if (port->readStarted >= QUEUE_SIZE) {
101            break;
102        }
103
104        req = DLIST_FIRST_ENTRY(pool, struct UsbFnRequest, list);
105        DListRemove(&req->list);
106        req->length = out->maxPacketSize;
107        ret = UsbFnSubmitRequestAsync(req);
108        if (ret != HDF_SUCCESS) {
109            HDF_LOGE("%{public}s: send request error %{public}d", __func__, ret);
110            DListInsertTail(&req->list, pool);
111            break;
112        }
113        port->readStarted++;
114        /* if ecm is disconnect, abort immediately */
115        if (port->ecm == NULL) {
116            break;
117        }
118    }
119    return port->readStarted;
120}
121
122static void UsbEcmRxPush(struct UsbEcm *port)
123{
124    struct DListHead *queue = &port->readQueue;
125    bool disconnect = false;
126
127    while (!DListIsEmpty(queue)) {
128        struct UsbFnRequest *req;
129
130        req = DLIST_FIRST_ENTRY(queue, struct UsbFnRequest, list);
131        switch (req->status) {
132            case USB_REQUEST_NO_DEVICE:
133                disconnect = true;
134                HDF_LOGV("%{public}s: the device is disconnected", __func__);
135                break;
136            case USB_REQUEST_COMPLETED:
137                break;
138            default:
139                HDF_LOGV("%{public}s: unexpected status %{public}d", __func__, req->status);
140                break;
141        }
142        if (req->actual && req->status == 0) {
143            uint32_t size = req->actual;
144            uint8_t *data = req->buf;
145            OsalMutexLock(&port->lockReadFifo);
146            if (DataFifoIsFull(&port->readFifo)) {
147                DataFifoSkip(&port->readFifo, size);
148            }
149            uint32_t count = DataFifoWrite(&port->readFifo, data, size);
150            if (count != size) {
151                HDF_LOGW("%{public}s: write %{public}u less than expected %{public}u", __func__, count, size);
152            }
153            OsalMutexUnlock(&port->lockReadFifo);
154        }
155        DListRemove(&req->list);
156        DListInsertTail(&req->list, &port->readPool);
157        port->readStarted--;
158    }
159
160    if (!disconnect && port->ecm) {
161        UsbEcmStartRx(port);
162    }
163}
164
165static void UsbEcmFreeRequests(const struct DListHead *head, int32_t *allocated)
166{
167    struct UsbFnRequest *req = NULL;
168    while (!DListIsEmpty(head)) {
169        req = DLIST_FIRST_ENTRY(head, struct UsbFnRequest, list);
170        DListRemove(&req->list);
171        (void)UsbFnFreeRequest(req);
172        if (allocated) {
173            (*allocated)--;
174        }
175    }
176}
177
178static void UsbEcmReadComplete(uint8_t pipe, struct UsbFnRequest *req)
179{
180    struct UsbEcm *port = (struct UsbEcm *)req->context;
181    OsalMutexLock(&port->lock);
182    DListInsertTail(&req->list, &port->readQueue);
183    UsbEcmRxPush(port);
184    OsalMutexUnlock(&port->lock);
185}
186
187static void UsbEcmWriteComplete(uint8_t pipe, struct UsbFnRequest *req)
188{
189    struct UsbEcm *port = (struct UsbEcm *)req->context;
190    OsalMutexLock(&port->lock);
191    DListInsertTail(&req->list, &port->writePool);
192    port->writeStarted--;
193
194    switch (req->status) {
195        case USB_REQUEST_COMPLETED:
196            UsbEcmStartTx(port);
197            break;
198        case USB_REQUEST_NO_DEVICE:
199            HDF_LOGV("%{public}s: ecm device was disconnected", __func__);
200            break;
201        default:
202            HDF_LOGV("%{public}s: unexpected status %{public}d", __func__, req->status);
203            break;
204    }
205    OsalMutexUnlock(&port->lock);
206}
207
208static int32_t UsbEcmAllocReadRequests(struct UsbEcm *port, int32_t num)
209{
210    struct UsbEcmDevice *ecm = port->ecm;
211    struct DListHead *head = &port->readPool;
212    struct UsbFnRequest *req = NULL;
213    int32_t i;
214
215    for (i = 0; i < num; i++) {
216        req = UsbFnAllocRequest(ecm->dataIface.handle, ecm->dataOutPipe.id, ecm->dataOutPipe.maxPacketSize);
217        if (!req) {
218            return DListIsEmpty(head) ? HDF_FAILURE : HDF_SUCCESS;
219        }
220
221        req->complete = UsbEcmReadComplete;
222        req->context = port;
223        DListInsertTail(&req->list, head);
224        port->readAllocated++;
225    }
226    return HDF_SUCCESS;
227}
228
229static int32_t UsbEcmAllocWriteRequests(struct UsbEcm *port, int32_t num)
230{
231    struct UsbEcmDevice *ecm = port->ecm;
232    struct DListHead *head = &port->writePool;
233    struct UsbFnRequest *req = NULL;
234    int32_t i;
235
236    for (i = 0; i < num; i++) {
237        req = UsbFnAllocRequest(ecm->dataIface.handle, ecm->dataInPipe.id, ecm->dataInPipe.maxPacketSize);
238        if (!req) {
239            return DListIsEmpty(head) ? HDF_FAILURE : HDF_SUCCESS;
240        }
241
242        req->complete = UsbEcmWriteComplete;
243        req->context = port;
244        DListInsertTail(&req->list, head);
245        port->writeAllocated++;
246    }
247    return HDF_SUCCESS;
248}
249
250static int32_t UsbEcmStartIo(struct UsbEcm *port)
251{
252    struct DListHead *head = &port->readPool;
253    int32_t ret = HDF_SUCCESS;
254    uint32_t started;
255
256    /* allocate requests for read/write */
257    if (port->readAllocated == 0) {
258        ret = UsbEcmAllocReadRequests(port, QUEUE_SIZE);
259        if (ret != HDF_SUCCESS) {
260            return ret;
261        }
262    }
263    if (port->writeAllocated == 0) {
264        ret = UsbEcmAllocWriteRequests(port, QUEUE_SIZE);
265        if (ret != HDF_SUCCESS) {
266            UsbEcmFreeRequests(head, &port->readAllocated);
267            return ret;
268        }
269    }
270
271    started = UsbEcmStartRx(port);
272    if (started) {
273        UsbEcmStartTx(port);
274    } else {
275        UsbEcmFreeRequests(head, &port->readAllocated);
276        UsbEcmFreeRequests(&port->writePool, &port->writeAllocated);
277        ret = HDF_ERR_IO;
278    }
279
280    return ret;
281}
282
283
284static int32_t UsbEcmAllocFifo(struct DataFifo *fifo, uint32_t size)
285{
286    if (!DataFifoIsInitialized(fifo)) {
287        void *data = OsalMemAlloc(size);
288        if (data == NULL) {
289            HDF_LOGE("%{public}s: allocate fifo data buffer failed", __func__);
290            return HDF_ERR_MALLOC_FAIL;
291        }
292        DataFifoInit(fifo, size, data);
293    }
294    return HDF_SUCCESS;
295}
296
297static int32_t UsbEcmOpen(struct UsbEcm *port)
298{
299    int32_t ret;
300
301    if (port == NULL) {
302        return HDF_ERR_INVALID_PARAM;
303    }
304
305    OsalMutexLock(&port->lock);
306    ret = UsbEcmAllocFifo(&port->writeFifo, WRITE_BUF_SIZE);
307    if (ret != HDF_SUCCESS) {
308        HDF_LOGE("%{public}s: UsbEcmAllocFifo failed", __func__);
309        goto OUT;
310    }
311    ret = UsbEcmAllocFifo(&port->readFifo, READ_BUF_SIZE);
312    if (ret != HDF_SUCCESS) {
313        HDF_LOGE("%{public}s: UsbEcmAllocFifo failed", __func__);
314        goto OUT;
315    }
316    DataFifoReset(&port->writeFifo);
317    DataFifoReset(&port->readFifo);
318
319    if (port->refCount++) {
320        HDF_LOGE("%{public}s: refCount failed", __func__);
321        goto OUT;
322    }
323
324    /* the ecm is enabled, start the io stream */
325    if (port->ecm) {
326        HDF_LOGD("%{public}s: start usb io", __func__);
327        ret = UsbEcmStartIo(port);
328        if (ret != HDF_SUCCESS) {
329            goto OUT;
330        }
331    }
332
333OUT:
334    OsalMutexUnlock(&port->lock);
335    return HDF_SUCCESS;
336}
337
338static int32_t UsbEcmClose(struct UsbEcm *port)
339{
340    if (port == NULL) {
341        return HDF_ERR_INVALID_PARAM;
342    }
343
344    OsalMutexLock(&port->lock);
345    if (port->refCount != 1) {
346        --port->refCount;
347        goto OUT;
348    }
349
350    HDF_LOGD("%{public}s: close usb serial", __func__);
351
352    DataFifoReset(&port->writeFifo);
353    DataFifoReset(&port->readFifo);
354    port->refCount = 0;
355
356OUT:
357    OsalMutexUnlock(&port->lock);
358    return HDF_SUCCESS;
359}
360
361static int32_t UsbEcmRead(struct UsbEcm *port, struct HdfSBuf *reply)
362{
363    uint32_t len;
364    int32_t ret = HDF_SUCCESS;
365    uint8_t *buf = NULL;
366    OsalMutexLock(&port->lock);
367    OsalMutexLock(&port->lockReadFifo);
368    if (DataFifoIsEmpty(&port->readFifo)) {
369        OsalMutexUnlock(&port->lockReadFifo);
370        OsalMutexUnlock(&port->lock);
371        return 0;
372    }
373
374    buf = (uint8_t *)OsalMemCalloc(DataFifoLen(&port->readFifo) + sizeof(uint32_t));
375    if (buf == NULL) {
376        HDF_LOGE("%{public}s: OsalMemCalloc error", __func__);
377        OsalMutexUnlock(&port->lockReadFifo);
378        OsalMutexUnlock(&port->lock);
379        return HDF_ERR_MALLOC_FAIL;
380    }
381
382    len = DataFifoRead(&port->readFifo, buf, DataFifoLen(&port->readFifo));
383    if (len == 0) {
384        HDF_LOGE("%{public}s: no data", __func__);
385        ret = HDF_ERR_IO;
386        OsalMutexUnlock(&port->lockReadFifo);
387        goto OUT;
388    }
389    OsalMutexUnlock(&port->lockReadFifo);
390
391    bool bufok = HdfSbufWriteBuffer(reply, (const void *)buf, len);
392    if (!bufok) {
393        HDF_LOGE("UsbEcmRead HdfSbufWriteBuffer error");
394        ret = HDF_ERR_IO;
395        goto OUT;
396    }
397
398OUT:
399    if (port->ecm) {
400        UsbEcmStartRx(port);
401    }
402    OsalMemFree(buf);
403    OsalMutexUnlock(&port->lock);
404    return ret;
405}
406
407static int32_t UsbEcmWrite(struct UsbEcm *port, struct HdfSBuf *data)
408{
409    uint32_t size = 0;
410    uint8_t *buf = NULL;
411
412    if (!HdfSbufReadBuffer(data, (const void **)&buf, &size)) {
413        HDF_LOGE("UsbEcmWrite HdfSbufReadBuffer err");
414        return HDF_ERR_IO;
415    }
416
417    OsalMutexLock(&port->lock);
418    if (size > 0 && buf != NULL) {
419        OsalMutexLock(&port->lockWriteFifo);
420        size = DataFifoWrite(&port->writeFifo, buf, size);
421        OsalMutexUnlock(&port->lockWriteFifo);
422    }
423    if (port->ecm) {
424        UsbEcmStartTx(port);
425    }
426    OsalMutexUnlock(&port->lock);
427    return HDF_SUCCESS;
428}
429
430void UsbFnNotifyRequest(struct UsbFnRequest *req, struct UsbEcmDevice *ecm)
431{
432    int32_t status;
433    ecm->notifyReq = NULL;
434    status = UsbFnSubmitRequestAsync(req);
435    if (status < 0) {
436        ecm->notifyReq = req;
437        HDF_LOGD("notify --> %{public}d", status);
438    }
439}
440
441static void EcmDoNotify(struct UsbEcmDevice *ecm)
442{
443    struct UsbFnRequest *req = ecm->notifyReq;
444    struct UsbCdcNotification *event = NULL;
445    uint32_t *data = NULL;
446
447    if (!req) {
448        return;
449    }
450    ecm->isOpen = true;
451    event = (struct UsbCdcNotification *)req->buf;
452    if (event == NULL) {
453        return;
454    }
455    switch (ecm->notifyState) {
456        case ECM_NOTIFY_NONE:
457            return;
458
459        case ECM_NOTIFY_CONNECT:
460            event->bNotificationType = USB_DDK_CDC_NOTIFY_NETWORK_CONNECTION;
461            if (ecm->isOpen) {
462                event->wValue = CPU_TO_LE16(1);
463            } else {
464                event->wValue = CPU_TO_LE16(0);
465            }
466            event->wLength = 0;
467            req->length = sizeof(*event);
468
469            HDF_LOGD("notify connect %{public}s", ecm->isOpen ? "true" : "false");
470            ecm->notifyState = ECM_NOTIFY_SPEED;
471            break;
472
473        case ECM_NOTIFY_SPEED:
474            event->bNotificationType = USB_DDK_CDC_NOTIFY_SPEED_CHANGE;
475            event->wValue = CPU_TO_LE16(0);
476            event->wLength = CPU_TO_LE16(0x08);
477            req->length = ECM_STATUS_BYTECOUNT;
478
479            /* SPEED_CHANGE data is up/down speeds in bits/sec */
480            data = (uint32_t *)((char *)req->buf + sizeof(*event));
481            data[0] = CPU_TO_LE32(EcmBitrate());
482            data[1] = data[0];
483
484            HDF_LOGD("notify speed %{public}d", EcmBitrate());
485            ecm->notifyState = ECM_NOTIFY_NONE;
486            break;
487
488        default:
489            break;
490    }
491    event->bmRequestType = 0xA1;
492    event->wIndex = CPU_TO_LE16(ecm->ctrlId);
493    UsbFnNotifyRequest(req, ecm);
494}
495
496static void EcmNotifyComplete(uint8_t pipe, struct UsbFnRequest *req)
497{
498    struct UsbEcmDevice *ecm = req->context;
499    struct UsbCdcNotification *event = req->buf;
500    ecm->notifyReq = req;
501    if (req->status == 0) {
502        EcmDoNotify(ecm);
503    } else {
504        HDF_LOGD("event %{public}d --> %{public}d", event->bNotificationType, req->status);
505    }
506}
507
508static int32_t EcmSetup(const struct UsbEcmDevice *ecm, const struct UsbFnCtrlRequest *ctrl)
509{
510    struct UsbFnRequest *req = ecm->ep0Req;
511    int32_t ret = -1;
512    uint16_t index = LE16_TO_CPU(ctrl->index);
513    uint16_t value = LE16_TO_CPU(ctrl->value);
514    uint16_t length = LE16_TO_CPU(ctrl->length);
515
516    switch ((ctrl->reqType << 0x08) | ctrl->request) {
517        case ((USB_DDK_DIR_OUT | USB_DDK_TYPE_CLASS | USB_DDK_RECIP_INTERFACE) << 0x08) |
518            USB_DDK_CDC_SET_ETHERNET_PACKET_FILTER:
519            if (length != 0 || index != ecm->ctrlId) {
520                break;
521            }
522            HDF_LOGD("packet filter %{public}02x", value);
523            ret = 0;
524            break;
525
526        default:
527            HDF_LOGW(
528                "invalid control req%{public}02x.%{public}02x v%{public}04x i%{public}04x l%{public}hu",
529                ctrl->reqType, ctrl->request, value, index, length);
530    }
531
532    if (ret >= 0) {
533        HDF_LOGD("ecm req%{public}02x.%{public}02x v%{public}04x i%{public}04x l%{public}d",
534            ctrl->reqType, ctrl->request, value, index, length);
535        req->length = (uint32_t)ret;
536        ret = UsbFnSubmitRequestSync(req, 0);
537        if (ret < 0) {
538            HDF_LOGD("ecm req %{public}02x.%{public}02x response err %{public}d", ctrl->reqType, ctrl->request, ret);
539        }
540    }
541
542    return value;
543}
544
545static int32_t EcmDeviceDispatch(
546    struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
547{
548    struct UsbEcmDevice *ecm = NULL;
549    struct UsbEcm *port = NULL;
550    int32_t ret;
551    if (client == NULL || client->device == NULL || client->device->service == NULL) {
552        HDF_LOGE("%{public}s: client is NULL", __func__);
553        return HDF_ERR_INVALID_OBJECT;
554    }
555    if (data == NULL || reply == NULL) {
556        HDF_LOGE("%{public}s: data or reply is NULL", __func__);
557        return HDF_ERR_INVALID_OBJECT;
558    }
559
560    if (HdfDeviceObjectCheckInterfaceDesc(client->device, data) == false) {
561        HDF_LOGE("%{public}s:%{public}d check interface desc fail", __func__, __LINE__);
562        return HDF_ERR_INVALID_PARAM;
563    }
564
565    switch (cmd) {
566        case USB_ECM_INIT:
567            return EcmInit(client->device);
568        case USB_ECM_RELEASE:
569            return EcmRelease(client->device);
570        default:
571            break;
572    }
573    ecm = (struct UsbEcmDevice *)client->device->service;
574    port = ecm->port;
575    if (port == NULL) {
576        return HDF_ERR_IO;
577    }
578    OsalMutexLock(&port->lockRW);
579    switch (cmd) {
580        case USB_ECM_OPEN:
581            ret = UsbEcmOpen(port);
582            break;
583        case USB_ECM_CLOSE:
584            ret = UsbEcmClose(port);
585            break;
586        case USB_ECM_READ:
587            ret = UsbEcmRead(port, reply);
588            break;
589        case USB_ECM_WRITE:
590            ret = UsbEcmWrite(port, data);
591            break;
592        default:
593            ret = HDF_ERR_NOT_SUPPORT;
594            break;
595    }
596    OsalMutexUnlock(&port->lockRW);
597    return ret;
598}
599
600static int32_t EcmEnable(struct UsbEcmDevice *ecm)
601{
602    (void)ecm;
603    return HDF_SUCCESS;
604}
605
606static void EcmDisable(const struct UsbEcmDevice *ecm)
607{
608    (void)ecm;
609    return;
610}
611
612static void UsbEcmEventCallback(struct UsbFnEvent *event)
613{
614    struct UsbEcmDevice *ecm = NULL;
615
616    if (event == NULL || event->context == NULL) {
617        HDF_LOGE("%{public}s: event is null", __func__);
618        return;
619    }
620
621    ecm = (struct UsbEcmDevice *)event->context;
622    switch (event->type) {
623        case USBFN_STATE_BIND:
624            HDF_LOGI("%{public}s: receive bind event", __func__);
625            break;
626        case USBFN_STATE_UNBIND:
627            HDF_LOGI("%{public}s: receive unbind event", __func__);
628            break;
629        case USBFN_STATE_ENABLE:
630            HDF_LOGI("%{public}s: receive enable event", __func__);
631            EcmEnable(ecm);
632            break;
633        case USBFN_STATE_DISABLE:
634            HDF_LOGI("%{public}s: receive disable event", __func__);
635            EcmDisable(ecm);
636            break;
637        case USBFN_STATE_SETUP:
638            HDF_LOGI("%{public}s: receive setup event", __func__);
639            if (event->setup != NULL) {
640                EcmSetup(ecm, event->setup);
641            }
642            break;
643        case USBFN_STATE_SUSPEND:
644            HDF_LOGI("%{public}s: receive suspend event", __func__);
645            break;
646        case USBFN_STATE_RESUME:
647            HDF_LOGI("%{public}s: receive resume event", __func__);
648            break;
649        default:
650            break;
651    }
652}
653
654static int32_t EcmAllocNotifyRequest(struct UsbEcmDevice *ecm)
655{
656    /* allocate notification request */
657    ecm->notifyReq =
658        UsbFnAllocRequest(ecm->ctrlIface.handle, ecm->notifyPipe.id, sizeof(struct UsbCdcNotification) * USBCDC_LEN);
659    if (ecm->notifyReq == NULL) {
660        HDF_LOGE("%{public}s: allocate notify request failed", __func__);
661        return HDF_FAILURE;
662    }
663    ecm->notifyReq->complete = EcmNotifyComplete;
664    ecm->notifyReq->context = ecm;
665
666    return HDF_SUCCESS;
667}
668
669static int32_t EcmAllocEp0Request(struct UsbEcmDevice *ecm)
670{
671    /* allocate notification request */
672    ecm->ep0Req = UsbFnAllocCtrlRequest(ecm->ctrlIface.handle, ECM_STATUS_BYTECOUNT);
673    if (ecm->ep0Req == NULL) {
674        HDF_LOGE("%{public}s: allocate ep0Req request failed", __func__);
675        return HDF_FAILURE;
676    }
677    return HDF_SUCCESS;
678}
679
680static int32_t EcmParseEachPipe(struct UsbEcmDevice *ecm, struct UsbEcmInterface *iface)
681{
682    struct UsbFnInterface *fnIface = iface->fn;
683    uint32_t repetIdx = 0;
684    for (int32_t i = 0; i < fnIface->info.numPipes; i++) {
685        struct UsbFnPipeInfo pipeInfo;
686        (void)memset_s(&pipeInfo, sizeof(pipeInfo), 0, sizeof(pipeInfo));
687        int32_t ret = UsbFnGetInterfacePipeInfo(fnIface, (uint8_t)i, &pipeInfo);
688        if (ret != HDF_SUCCESS) {
689            HDF_LOGE("%{public}s: get pipe info error", __func__);
690            return HDF_FAILURE;
691        }
692
693        switch (pipeInfo.type) {
694            case USB_PIPE_TYPE_INTERRUPT:
695                ecm->notifyPipe.id = pipeInfo.id;
696                ecm->notifyPipe.maxPacketSize = pipeInfo.maxPacketSize;
697                ecm->ctrlIface = *iface;
698                break;
699            case USB_PIPE_TYPE_BULK:
700                if (pipeInfo.dir == USB_PIPE_DIRECTION_IN) {
701                    ecm->dataInPipe.id = pipeInfo.id;
702                    ecm->dataInPipe.maxPacketSize = pipeInfo.maxPacketSize;
703                    ecm->dataIface = *iface;
704                } else {
705                    ecm->dataOutPipe.id = pipeInfo.id;
706                    ecm->dataOutPipe.maxPacketSize = pipeInfo.maxPacketSize;
707                }
708                break;
709            default:
710                if (repetIdx < WAIT_UDC_MAX_LOOP) {
711                    usleep(WAIT_UDC_TIME);
712                    i--;
713                }
714                repetIdx++;
715                HDF_LOGE("%{public}s: pipe type %{public}d don't support", __func__, pipeInfo.type);
716                break;
717        }
718    }
719
720    return HDF_SUCCESS;
721}
722
723static int32_t EcmParseEcmIface(struct UsbEcmDevice *ecm, struct UsbFnInterface *fnIface)
724{
725    int32_t ret;
726    struct UsbEcmInterface iface;
727    UsbFnInterfaceHandle handle = UsbFnOpenInterface(fnIface);
728    if (handle == NULL) {
729        HDF_LOGE("%{public}s: open interface failed", __func__);
730        return HDF_FAILURE;
731    }
732    iface.fn = fnIface;
733    iface.handle = handle;
734
735    ret = EcmParseEachPipe(ecm, &iface);
736    if (ret != HDF_SUCCESS) {
737        return HDF_FAILURE;
738    }
739    return HDF_SUCCESS;
740}
741
742static int32_t EcmParseEachIface(struct UsbEcmDevice *ecm, struct UsbFnDevice *fnDev)
743{
744    struct UsbFnInterface *fnIface = NULL;
745    uint32_t i;
746
747    for (i = 0; i < fnDev->numInterfaces; i++) {
748        fnIface = (struct UsbFnInterface *)UsbFnGetInterface(fnDev, i);
749        if (fnIface == NULL) {
750            HDF_LOGE("%{public}s: get interface failed", __func__);
751            return HDF_FAILURE;
752        }
753
754        if (fnIface->info.subclass == USB_DDK_CDC_SUBCLASS_ETHERNET) {
755            (void)EcmParseEcmIface(ecm, fnIface);
756            fnIface = (struct UsbFnInterface *)UsbFnGetInterface(fnDev, i + 1);
757            if (fnIface == NULL) {
758                HDF_LOGE("%{public}s: get interface failed", __func__);
759                return HDF_FAILURE;
760            }
761            (void)EcmParseEcmIface(ecm, fnIface);
762            return HDF_SUCCESS;
763        }
764    }
765
766    return HDF_FAILURE;
767}
768
769static int32_t EcmCreateFuncDevice(struct UsbEcmDevice *ecm, struct DeviceResourceIface *iface)
770{
771    struct UsbFnDevice *fnDev = NULL;
772    int32_t ret;
773
774    if (iface->GetString(ecm->device->property, "udc_name", (const char **)&ecm->udcName, UDC_NAME) != HDF_SUCCESS) {
775        HDF_LOGE("%{public}s: read udc_name failed, use default", __func__);
776        return HDF_FAILURE;
777    }
778
779    fnDev = (struct UsbFnDevice *)UsbFnGetDevice(ecm->udcName);
780    if (fnDev == NULL) {
781        HDF_LOGE("%{public}s: create usb function device failed", __func__);
782        return HDF_FAILURE;
783    }
784
785    ret = EcmParseEachIface(ecm, fnDev);
786    if (ret != HDF_SUCCESS) {
787        HDF_LOGE("%{public}s: get pipes failed", __func__);
788        goto ERR;
789    }
790
791    ecm->fnDev = fnDev;
792    return HDF_SUCCESS;
793
794ERR:
795    return ret;
796}
797
798static void EcmFreeNotifyRequest(struct UsbEcmDevice *ecm)
799{
800    int32_t ret;
801
802    /* free notification request */
803    ret = UsbFnFreeRequest(ecm->notifyReq);
804    if (ret != HDF_SUCCESS) {
805        HDF_LOGE("%{public}s: free notify request failed", __func__);
806        return;
807    }
808    ecm->notifyReq = NULL;
809}
810
811static int32_t EcmReleaseFuncDevice(struct UsbEcmDevice *ecm)
812{
813    int32_t ret = HDF_SUCCESS;
814    if (ecm->fnDev == NULL) {
815        HDF_LOGE("%{public}s: fnDev is null", __func__);
816        return HDF_FAILURE;
817    }
818    (void)UsbFnFreeRequest(ecm->ep0Req);
819    (void)EcmFreeNotifyRequest(ecm);
820    UsbFnCloseInterface(ecm->ctrlIface.handle);
821    (void)UsbFnCloseInterface(ecm->dataIface.handle);
822    (void)UsbFnStopRecvInterfaceEvent(ecm->ctrlIface.fn);
823    return ret;
824}
825
826static int32_t UsbEcmAlloc(struct UsbEcmDevice *ecm)
827{
828    struct UsbEcm *port = NULL;
829
830    port = (struct UsbEcm *)OsalMemCalloc(sizeof(*port));
831    if (port == NULL) {
832        HDF_LOGE("%{public}s: Alloc usb serial port failed", __func__);
833        return HDF_FAILURE;
834    }
835
836    if (OsalMutexInit(&port->lock) != HDF_SUCCESS) {
837        HDF_LOGE("%{public}s: init lock fail!", __func__);
838        OsalMemFree(port);
839        return HDF_FAILURE;
840    }
841
842    if (OsalMutexInit(&port->lockRW) != HDF_SUCCESS) {
843        HDF_LOGE("%{public}s: init lock fail!", __func__);
844        OsalMutexDestroy(&port->lock);
845        OsalMemFree(port);
846        return HDF_FAILURE;
847    }
848
849    if (OsalMutexInit(&port->lockReadFifo) != HDF_SUCCESS) {
850        HDF_LOGE("%{public}s: init lock fail!", __func__);
851        OsalMutexDestroy(&port->lock);
852        OsalMutexDestroy(&port->lockRW);
853        OsalMemFree(port);
854        return HDF_FAILURE;
855    }
856
857    if (OsalMutexInit(&port->lockWriteFifo) != HDF_SUCCESS) {
858        HDF_LOGE("%{public}s: init lock fail!", __func__);
859        OsalMutexDestroy(&port->lock);
860        OsalMutexDestroy(&port->lockRW);
861        OsalMutexDestroy(&port->lockReadFifo);
862        OsalMemFree(port);
863        return HDF_FAILURE;
864    }
865    DListHeadInit(&port->readPool);
866    DListHeadInit(&port->readQueue);
867    DListHeadInit(&port->writePool);
868
869    ecm->port = port;
870    return HDF_SUCCESS;
871}
872
873static void UsbEcmFree(struct UsbEcmDevice *ecm)
874{
875    if (ecm != NULL && ecm->port != NULL) {
876        OsalMutexDestroy(&ecm->port->lock);
877        OsalMutexDestroy(&ecm->port->lockRW);
878        OsalMutexDestroy(&ecm->port->lockReadFifo);
879        OsalMutexDestroy(&ecm->port->lockWriteFifo);
880        OsalMemFree(ecm->port);
881        ecm->port = NULL;
882    }
883}
884
885/* HdfDriverEntry implementations */
886static int32_t EcmDriverBind(struct HdfDeviceObject *device)
887{
888    struct UsbEcmDevice *ecm = NULL;
889
890    if (device == NULL) {
891        HDF_LOGE("%{public}s: device is null", __func__);
892        return HDF_ERR_INVALID_OBJECT;
893    }
894
895    ecm = (struct UsbEcmDevice *)OsalMemCalloc(sizeof(*ecm));
896    if (ecm == NULL) {
897        HDF_LOGE("%{public}s: Alloc usb ecm device failed", __func__);
898        return HDF_FAILURE;
899    }
900    ecm->ctrlId = 0;
901    ecm->dataId = 1;
902    if (OsalMutexInit(&ecm->lock) != HDF_SUCCESS) {
903        HDF_LOGE("%{public}s: init lock fail!", __func__);
904        OsalMemFree(ecm);
905        return HDF_FAILURE;
906    }
907
908    if (HdfDeviceObjectSetInterfaceDesc(device, "hdf.usb.usbfn") != HDF_SUCCESS) {
909        HDF_LOGE(" Set Desc fail!");
910        OsalMemFree(ecm);
911        return HDF_FAILURE;
912    }
913
914    ecm->device = device;
915    device->service = &(ecm->service);
916    if (ecm->device->service) {
917        ecm->device->service->Dispatch = EcmDeviceDispatch;
918    }
919    return HDF_SUCCESS;
920}
921
922static int32_t EcmInit(struct HdfDeviceObject *device)
923{
924    struct UsbEcmDevice *ecm = NULL;
925    struct DeviceResourceIface *iface = NULL;
926    int32_t ret;
927
928    if (device == NULL) {
929        HDF_LOGE("%{public}s: device is null", __func__);
930        return HDF_ERR_INVALID_OBJECT;
931    }
932
933    ecm = (struct UsbEcmDevice *)device->service;
934    if (ecm == NULL || ecm->initFlag) {
935        HDF_LOGE("%{public}s: ecm is null", __func__);
936        return HDF_FAILURE;
937    }
938
939    iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
940    if (iface == NULL || iface->GetUint32 == NULL) {
941        HDF_LOGE("%{public}s: face is invalid", __func__);
942        return HDF_FAILURE;
943    }
944
945    ret = EcmCreateFuncDevice(ecm, iface);
946    if (ret != HDF_SUCCESS) {
947        HDF_LOGE("%{public}s: EcmCreateFuncDevice failed", __func__);
948        return ret;
949    }
950
951    ret = UsbEcmAlloc(ecm);
952    if (ret != HDF_SUCCESS) {
953        HDF_LOGE("%{public}s: UsbEcmAlloc failed", __func__);
954        return ret;
955    }
956
957    ret = EcmAllocEp0Request(ecm);
958    if (ret != HDF_SUCCESS) {
959        HDF_LOGE("%{public}s: EcmAllocEp0Request failed", __func__);
960        goto ERR;
961    }
962
963    ret = EcmAllocNotifyRequest(ecm);
964    if (ret != HDF_SUCCESS) {
965        HDF_LOGE("%{public}s: EcmAllocNotifyRequest failed", __func__);
966        goto ERR;
967    }
968
969    ret = UsbFnStartRecvInterfaceEvent(ecm->ctrlIface.fn, RECEIVE_ALL_EVENTS, UsbEcmEventCallback, ecm);
970    if (ret != HDF_SUCCESS) {
971        HDF_LOGE("%{public}s: register event callback failed", __func__);
972        goto ERR;
973    }
974    ecm->initFlag = true;
975    return ret;
976ERR:
977    UsbEcmFree(ecm);
978    (void)EcmReleaseFuncDevice(ecm);
979    return ret;
980}
981
982static int32_t EcmRelease(struct HdfDeviceObject *device)
983{
984    struct UsbEcmDevice *ecm = NULL;
985
986    if (device == NULL) {
987        HDF_LOGE("%{public}s: device is NULL", __func__);
988        return HDF_FAILURE;
989    }
990
991    ecm = (struct UsbEcmDevice *)device->service;
992    if (ecm == NULL) {
993        HDF_LOGE("%{public}s: ecm is null", __func__);
994        return HDF_FAILURE;
995    }
996    if (ecm->initFlag == false) {
997        HDF_LOGE("%{public}s: ecm not init!", __func__);
998        return HDF_FAILURE;
999    }
1000    UsbEcmFree(ecm);
1001    (void)EcmReleaseFuncDevice(ecm);
1002    ecm->initFlag = false;
1003    return HDF_SUCCESS;
1004}
1005
1006static int32_t EcmDriverInit(struct HdfDeviceObject *device)
1007{
1008    (void)device;
1009    HDF_LOGE("%{public}s: usbfn do nothing...", __func__);
1010    return 0;
1011}
1012
1013static void EcmDriverRelease(struct HdfDeviceObject *device)
1014{
1015    struct UsbEcmDevice *ecm = NULL;
1016    if (device == NULL) {
1017        HDF_LOGE("%{public}s: device is NULL", __func__);
1018        return;
1019    }
1020
1021    ecm = (struct UsbEcmDevice *)device->service;
1022    if (ecm == NULL) {
1023        HDF_LOGE("%{public}s: ecm is null", __func__);
1024        return;
1025    }
1026
1027    (void)OsalMutexDestroy(&ecm->lock);
1028    OsalMemFree(ecm);
1029    device->service = NULL;
1030}
1031
1032struct HdfDriverEntry g_ecmDriverEntry = {
1033    .moduleVersion = 1,
1034    .moduleName = "usbfn_cdcecm",
1035    .Bind = EcmDriverBind,
1036    .Init = EcmDriverInit,
1037    .Release = EcmDriverRelease,
1038};
1039
1040HDF_INIT(g_ecmDriverEntry);
1041