From ea1beea612b198f841176ea440e949c89a3a2a03 Mon Sep 17 00:00:00 2001 From: sakimisu <1203593632@qq.com> Date: Mon, 28 Nov 2022 22:28:37 +0800 Subject: [PATCH] add rt-thread dfs and rndis host port --- third_party/rt-thread-4.1.1/dfs/udisk.c | 342 +++++++++ .../rt-thread-4.1.1/rndis_host/rndis_host.c | 690 ++++++++++++++++++ 2 files changed, 1032 insertions(+) create mode 100644 third_party/rt-thread-4.1.1/dfs/udisk.c create mode 100644 third_party/rt-thread-4.1.1/rndis_host/rndis_host.c diff --git a/third_party/rt-thread-4.1.1/dfs/udisk.c b/third_party/rt-thread-4.1.1/dfs/udisk.c new file mode 100644 index 00000000..64ff590f --- /dev/null +++ b/third_party/rt-thread-4.1.1/dfs/udisk.c @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-12-12 Yi Qiu first version + */ + +#include +#include + +#include "usbh_core.h" +#include "usbh_msc.h" + +#define MAX_PARTITION_COUNT 5 + +struct ustor_data { + struct dfs_partition part; + struct usbh_msc *msc_class; + int udisk_id; + const char path; +}; + +struct ustor { + rt_uint32_t capicity[2]; + + struct rt_device dev[MAX_PARTITION_COUNT]; + rt_uint8_t dev_cnt; +}; +typedef struct ustor *ustor_t; + +#define UDISK_MAX_COUNT 8 +static rt_uint8_t _udisk_idset = 0; + +ustor_t stor_r; + +static int udisk_get_id(void) +{ + int i; + + for (i = 0; i < UDISK_MAX_COUNT; i++) { + if ((_udisk_idset & (1 << i)) != 0) + continue; + else + break; + } + + /* it should not happen */ + if (i == UDISK_MAX_COUNT) + RT_ASSERT(0); + + _udisk_idset |= (1 << i); + return i; +} + +static void udisk_free_id(int id) +{ + RT_ASSERT(id < UDISK_MAX_COUNT) + + _udisk_idset &= ~(1 << id); +} + +/** + * This function will initialize the udisk device + * + * @param dev the pointer of device driver structure + * + * @return RT_EOK + */ +static rt_err_t rt_udisk_init(rt_device_t dev) +{ + return RT_EOK; +} + +/** + * This function will read some data from a device. + * + * @param dev the pointer of device driver structure + * @param pos the position of reading + * @param buffer the data buffer to save read data + * @param size the size of buffer + * + * @return the actually read size on successful, otherwise negative returned. + */ +static rt_size_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer, + rt_size_t size) +{ + rt_err_t ret; + struct usbh_msc *msc_class; + struct ustor_data *data; + + /* check parameter */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + + data = (struct ustor_data *)dev->user_data; + msc_class = data->msc_class; + + ret = usbh_msc_scsi_read10(msc_class, pos, (rt_uint8_t *)buffer, size); + + if (ret != RT_EOK) { + rt_kprintf("usb mass_storage read failed\n"); + return 0; + } + + return size; +} + +/** + * This function will write some data to a device. + * + * @param dev the pointer of device driver structure + * @param pos the position of written + * @param buffer the data buffer to be written to device + * @param size the size of buffer + * + * @return the actually written size on successful, otherwise negative returned. + */ +static rt_size_t rt_udisk_write(rt_device_t dev, rt_off_t pos, const void *buffer, + rt_size_t size) +{ + rt_err_t ret; + struct usbh_msc *msc_class; + struct ustor_data *data; + + /* check parameter */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + + data = (struct ustor_data *)dev->user_data; + msc_class = data->msc_class; + + ret = usbh_msc_scsi_write10(msc_class, pos, (rt_uint8_t *)buffer, size); + if (ret != RT_EOK) { + rt_kprintf("usb mass_storage write %d sector failed\n", size); + return 0; + } + + return size; +} + +/** + * This function will execute SCSI_INQUIRY_CMD command to get inquiry data. + * + * @param intf the interface instance. + * @param buffer the data buffer to save inquiry data + * + * @return the error code, RT_EOK on successfully. + */ +static rt_err_t rt_udisk_control(rt_device_t dev, int cmd, void *args) +{ + struct ustor_data *data; + + /* check parameter */ + RT_ASSERT(dev != RT_NULL); + + data = (struct ustor_data *)dev->user_data; + + if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) { + struct rt_device_blk_geometry *geometry; + + geometry = (struct rt_device_blk_geometry *)args; + if (geometry == RT_NULL) + return -RT_ERROR; + + geometry->bytes_per_sector = SECTOR_SIZE; + geometry->block_size = stor_r->capicity[1]; + geometry->sector_count = stor_r->capicity[0]; + } + + return RT_EOK; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops udisk_device_ops = { + rt_udisk_init, + RT_NULL, + RT_NULL, + rt_udisk_read, + rt_udisk_write, + rt_udisk_control +}; +#endif + +/** + * This function will run udisk driver when usb disk is detected. + * + * @param intf the usb interface instance. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_udisk_run(struct usbh_msc *msc_class) +{ + int i = 0; + rt_err_t ret; + char dname[8]; + char sname[8]; + rt_uint8_t max_lun, *sector, sense[18], inquiry[36]; + struct dfs_partition part[MAX_PARTITION_COUNT]; + + /* check parameter */ + RT_ASSERT(msc_class != RT_NULL); + stor_r = (struct ustor *)rt_malloc(sizeof(struct ustor)); + rt_memset(stor_r, 0, sizeof(struct ustor)); + + /* get the first sector to read partition table */ + sector = (rt_uint8_t *)rt_malloc(SECTOR_SIZE); + if (sector == RT_NULL) { + rt_kprintf("allocate partition sector buffer failed\n"); + return -RT_ERROR; + } + + rt_memset(sector, 0, SECTOR_SIZE); + + /* get the partition table */ + ret = usbh_msc_scsi_read10(msc_class, 0, sector, 1); + if (ret != RT_EOK) { + rt_kprintf("read parition table error\n"); + + rt_free(sector); + return -RT_ERROR; + } + + for (i = 0; i < MAX_PARTITION_COUNT; i++) { + /* get the first partition */ + ret = dfs_filesystem_get_partition(&part[i], sector, i); + if (ret == RT_EOK) { + struct ustor_data *data = rt_malloc(sizeof(struct ustor_data)); + rt_memset(data, 0, sizeof(struct ustor_data)); + data->msc_class = msc_class; + data->udisk_id = udisk_get_id(); + rt_snprintf(dname, 6, "ud%d-%d", data->udisk_id, i); + rt_snprintf(sname, 8, "sem_ud%d", i); + data->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO); + + /* register sdcard device */ + stor_r->dev[i].type = RT_Device_Class_Block; +#ifdef RT_USING_DEVICE_OPS + stor->dev[i].ops = &udisk_device_ops; +#else + stor_r->dev[i].init = rt_udisk_init; + stor_r->dev[i].read = rt_udisk_read; + stor_r->dev[i].write = rt_udisk_write; + stor_r->dev[i].control = rt_udisk_control; +#endif + stor_r->dev[i].user_data = (void *)data; + + rt_device_register(&stor_r->dev[i], dname, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); + + stor_r->dev_cnt++; + + if (dfs_mount(stor_r->dev[i].parent.name, "/", "elm", 0, 0) == 0) { + rt_kprintf("udisk part %d mount successfully\n", i); + } else { + rt_kprintf("udisk part %d mount failed\n", i); + } + } else { + if (i == 0) { + struct ustor_data *data = rt_malloc(sizeof(struct ustor_data)); + rt_memset(data, 0, sizeof(struct ustor_data)); + data->udisk_id = udisk_get_id(); + + /* there is no partition table */ + data->part.offset = 0; + data->part.size = 0; + data->msc_class = msc_class; + data->part.lock = rt_sem_create("sem_ud", 1, RT_IPC_FLAG_FIFO); + + rt_snprintf(dname, 7, "udisk%d", data->udisk_id); + + /* register sdcard device */ + stor_r->dev[0].type = RT_Device_Class_Block; +#ifdef RT_USING_DEVICE_OPS + stor->dev[i].ops = &udisk_device_ops; +#else + stor_r->dev[0].init = rt_udisk_init; + stor_r->dev[0].read = rt_udisk_read; + stor_r->dev[0].write = rt_udisk_write; + stor_r->dev[0].control = rt_udisk_control; +#endif + stor_r->dev[0].user_data = (void *)data; + + rt_device_register(&stor_r->dev[0], dname, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); + + stor_r->dev_cnt++; + if (dfs_mount(stor_r->dev[0].parent.name, "/", "elm", 0, 0) == 0) { + rt_kprintf("Mount FAT on Udisk successful.\n"); + } else { + rt_kprintf("Mount FAT on Udisk failed.\n"); + } + } + + break; + } + } + + rt_free(sector); + + return RT_EOK; +} + +/** + * This function will be invoked when usb disk plug out is detected and it would clean + * and release all udisk related resources. + * + * @param intf the usb interface instance. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_udisk_stop(struct usbh_msc *msc_class) +{ + int i; + + struct ustor_data *data; + + /* check parameter */ + RT_ASSERT(msc_class != RT_NULL); + + RT_ASSERT(stor_r != RT_NULL); + + for (i = 0; i < stor_r->dev_cnt; i++) { + rt_device_t dev = &stor_r->dev[i]; + data = (struct ustor_data *)dev->user_data; + + /* unmount filesystem */ + dfs_unmount("/"); + + /* delete semaphore */ + rt_sem_delete(data->part.lock); + udisk_free_id(data->udisk_id); + rt_free(data); + + /* unregister device */ + rt_device_unregister(&stor_r->dev[i]); + } + + rt_free(stor_r); + + return RT_EOK; +} \ No newline at end of file diff --git a/third_party/rt-thread-4.1.1/rndis_host/rndis_host.c b/third_party/rt-thread-4.1.1/rndis_host/rndis_host.c new file mode 100644 index 00000000..64707bca --- /dev/null +++ b/third_party/rt-thread-4.1.1/rndis_host/rndis_host.c @@ -0,0 +1,690 @@ +#include +#include "usbh_core.h" +#include "usbh_rndis.h" +#include "rndis_protocol.h" + +/* RT-Thread LWIP ethernet interface */ +#include +#include + +/* define the rdnis device state*/ +#define RNDIS_BUS_UNINITIALIZED 0 +#define RNDIS_BUS_INITIALIZED 1 +#define RNDIS_INITIALIZED 2 +#define RNDIS_DATA_INITIALIZED 3 + +#define USB_ETH_MTU 1500 + 14 +#define RNDIS_MESSAGE_BUFFER_SIZE 128 +#define RNDIS_INFO_BUFFER_OFFSET 20 + +// #define RESPONSE_AVAILABLE 0x00000001 + +/* rndis device power off time, unit:ms, 0:power off always */ +#ifndef RNDIS_DEV_POWER_OFF_TIME +#define RNDIS_DEV_POWER_OFF_TIME 0 +#endif + +#define RNDIS_NET_DEV_NAME "u0" +#define MAX_ADDR_LEN 6 +/* rndis device keepalive time 5000ms*/ +#define RNDIS_DEV_KEEPALIVE_TIMEOUT 5000 +/*should be the usb Integer multiple of maximum packet length N*64*/ +#define RNDIS_ETH_BUFFER_LEN (sizeof(struct rndis_packet_msg) + USB_ETH_MTU + 42) + +struct rndis_packet_msg +{ + rt_uint32_t MessageType; + rt_uint32_t MessageLength; + rt_uint32_t DataOffset; + rt_uint32_t DataLength; + rt_uint32_t OOBDataOffset; + rt_uint32_t OOBDataLength; + rt_uint32_t NumOOBDataElements; + rt_uint32_t PerPacketInfoOffset; + rt_uint32_t PerPacketInfoLength; + rt_uint32_t VcHandle; + rt_uint32_t Reserved; + rt_uint8_t data[0]; +}; +typedef struct rndis_packet_msg* rndis_packet_msg_t; + +struct rt_rndis_eth { + /* inherit from ethernet device */ + struct eth_device parent; + + struct usbh_rndis *rndis_class; + rt_mutex_t rndis_mutex; + /* interface address info */ + rt_uint8_t dev_addr[MAX_ADDR_LEN]; + rt_uint16_t res; + rt_uint32_t rndis_speed; + rt_uint32_t res32; + + rt_uint8_t tx_buffer[RNDIS_ETH_BUFFER_LEN]; + rt_uint8_t rx_bufferA[RNDIS_ETH_BUFFER_LEN]; + rt_uint8_t rx_bufferB[RNDIS_ETH_BUFFER_LEN]; + rt_size_t rx_lengthA; + rt_size_t rx_lengthB; + rt_uint8_t *rx_buf_ptr; + rt_uint32_t frame_debug; + rt_uint32_t send_packet_counter; + rt_uint32_t recv_packet_counter; + + rt_uint32_t rndis_state; + rt_thread_t rndis_recv; + rt_timer_t keepalive_timer; +}; +typedef struct rt_rndis_eth *rt_rndis_eth_t; + +void hex_data_print(const char *name, const rt_uint8_t *buf, rt_size_t size) +{ +#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ') +#define WIDTH_SIZE 32 + + rt_size_t i, j; + rt_tick_t tick = 0; + rt_uint32_t time = 0; + + tick = rt_tick_get(); + time = (tick * 1000) / RT_TICK_PER_SECOND; + + rt_kprintf("%s time=%d.%ds,len = %d\n", name, time / 1000, time % 1000, size); + + for (i = 0; i < size; i += WIDTH_SIZE) { + rt_kprintf("[HEX] %s: %04X-%04X: ", name, i, i + WIDTH_SIZE); + for (j = 0; j < WIDTH_SIZE; j++) { + if (i + j < size) { + rt_kprintf("%02X ", buf[i + j]); + } else { + rt_kprintf(" "); + } + if ((j + 1) % 8 == 0) { + rt_kprintf(" "); + } + } + rt_kprintf(" "); + for (j = 0; j < WIDTH_SIZE; j++) { + if (i + j < size) { + rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.'); + } + } + rt_kprintf("\n"); + } +} + +#define RNDIS_DEV_DEBUG +#ifdef RNDIS_DEV_DEBUG +#define RNDIS_DEV_PRINTF \ + rt_kprintf("[RNDIS_DEV] "); \ + rt_kprintf +#else +#define RNDIS_DEV_PRINTF(...) +#endif /* RNDIS_DEBUG */ + +static struct rt_rndis_eth usbh_rndis_eth_device; + +/** + * This function send the rndis data. + * + * @param rndis_class the usb interface instance. + * + * @return the error code, RT_EOK on successfully. + */ +static rt_err_t rt_rndis_msg_data_send(struct usbh_rndis *rndis_class, rt_uint8_t *buffer, int nbytes) +{ + int ret = 0; + + if (rndis_class == RT_NULL) { + return -RT_ERROR; + } + + rt_rndis_eth_t info = RT_NULL; + + info = (rt_rndis_eth_t)rndis_class->user_data; + + ret = usbh_rndis_bulk_out_transfer(rndis_class, buffer, nbytes, 5000); + if (ret != nbytes) { + rt_kprintf("rndis msg send fial\r\n"); + } + rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER); + if (info->keepalive_timer) { + rt_timer_start(info->keepalive_timer); + } + rt_mutex_release(usbh_rndis_eth_device.rndis_mutex); + + return ret; +} + +/** + * This function recv the rndis data. + * + * @param rndis_class the usb interface instance. + * + * @return the error code, RT_EOK on successfully. + */ +static rt_err_t rndis_msg_data_recv(struct usbh_rndis *rndis_class, rt_uint8_t *buffer, int nbytes) +{ + int ret = 0; + + if (rndis_class == RT_NULL) { + return -RT_ERROR; + } + + rt_rndis_eth_t info = RT_NULL; + + info = (rt_rndis_eth_t)rndis_class->user_data; + + ret = usbh_rndis_bulk_in_transfer(rndis_class, buffer, nbytes, 3); + rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER); + if (info->keepalive_timer) { + rt_timer_start(info->keepalive_timer); + } + rt_mutex_release(usbh_rndis_eth_device.rndis_mutex); + + return ret; +} + +/** + * This function send the rndis set msg. + * + * @param rndis_class the usb interface instance. + * + * @return the error code, RT_EOK on successfully. + */ +static rt_err_t rt_rndis_keepalive_msg(struct usbh_rndis *rndis_class) +{ + return usbh_rndis_keepalive(rndis_class); +} + +/** + * This function will send the bulk data to the usb device instance, + * + * @param device the usb device instance. + * @param type the type of descriptor bRequest. + * @param buffer the data buffer to save requested data + * @param nbytes the size of buffer + * + * @return the error code, RT_EOK on successfully. + */ +void rt_usbh_rndis_data_recv_entry(void *pdata) +{ + int ret = 0; + struct usbh_rndis *rndis_class = (struct usbh_rndis *)pdata; + rt_rndis_eth_t device = RT_NULL; + rndis_packet_msg_t pmsg = RT_NULL; + device = (rt_rndis_eth_t)rndis_class->user_data; + + if ((pdata == RT_NULL) || (rndis_class == RT_NULL) || + (device == RT_NULL)) { + return; + } + + while (1) { + ret = rndis_msg_data_recv(rndis_class, device->rx_buf_ptr, RNDIS_ETH_BUFFER_LEN); + if (ret > 0) { + pmsg = (rndis_packet_msg_t)device->rx_buf_ptr; + + if (device->frame_debug == RT_TRUE) { + hex_data_print("rndis eth rx", device->rx_buf_ptr, ret); + } + if (device->rx_buf_ptr == device->rx_bufferA) { + if (device->rx_lengthA) { + RNDIS_DEV_PRINTF("Rndis deivce rx bufferA overwrite!\n"); + } + device->rx_lengthA = ret; + device->rx_buf_ptr = device->rx_bufferB; + } else { + if (device->rx_lengthB) { + RNDIS_DEV_PRINTF("Rndis deivce rx bufferB overwrite!\n"); + } + device->rx_lengthB = ret; + device->rx_buf_ptr = device->rx_bufferA; + } + + if ((pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) && (pmsg->MessageLength == ret)) { + device->recv_packet_counter++; + eth_device_ready((struct eth_device *)device); + } else { + RNDIS_DEV_PRINTF("Rndis deivce recv data error!\n"); + } + } + + if (ret == 0) { + ret = 0; + rt_thread_mdelay(10); + } else { + ret -= 1; + device->recv_packet_counter += 0; + rt_thread_mdelay(10); + } + } +} + +/** + * This function power off the rndis device and power up it again. + * + * @rndis_class intf the usb interface instance. + * + * @return the error code, RT_EOK on successfully. + */ +static rt_err_t rt_rndis_dev_power(struct usbh_rndis *rndis_class, rt_uint32_t time) +{ + /*power off the rndis device*/ + // rt_usbh_hub_clear_port_feature(intf->device->parent_hub, intf->device->port, PORT_FEAT_POWER); + // if(time) + // { + // rt_thread_mdelay(time); + // /*power up the rndis device */ + // rt_usbh_hub_set_port_feature(intf->device->parent_hub, intf->device->port, PORT_FEAT_POWER); + // } + + return RT_EOK; +} + +void rt_rndis_dev_keepalive_timeout(void *pdata) +{ + struct usbh_rndis *rndis_class = (struct usbh_rndis *)pdata; + static rt_uint32_t keepalive_error = 0; + + if (rndis_class == RT_NULL) { + return; + } + + rt_rndis_eth_t info = RT_NULL; + + info = (rt_rndis_eth_t)rndis_class->user_data; + + if (RT_EOK == rt_rndis_keepalive_msg(rndis_class)) { + RNDIS_DEV_PRINTF("rndis dev keepalive success!\n"); + keepalive_error = 0; + rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER); + if (info->keepalive_timer) { + rt_timer_start(info->keepalive_timer); + } + rt_mutex_release(usbh_rndis_eth_device.rndis_mutex); + } else { + keepalive_error++; + RNDIS_DEV_PRINTF("rndis dev keepalive timeout!\n"); + if (keepalive_error > 3) { + keepalive_error = 0; + rt_rndis_dev_power(rndis_class, RNDIS_DEV_POWER_OFF_TIME); + info->rndis_state = RNDIS_BUS_INITIALIZED; + } + } +} + +/** + * This function will run rndis driver when usb disk is detected. + * + * @param rndis_class the usb interface instance. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_rndis_run(struct usbh_rndis *rndis_class, struct rndis_dev_info *dev_info) +{ + rt_err_t ret = 0; + // urndis_t rndis = RT_NULL; + rt_uint8_t *recv_buf = RT_NULL; + rt_uint32_t recv_len = 256; + rt_uint32_t *psupport_oid_list = RT_NULL; + rt_uint32_t *poid = RT_NULL; + rt_uint32_t *pquery_rlt = RT_NULL; + rt_uint32_t i = 0, j = 0; + rt_uint32_t oid_len = 0; + struct netdev *netdev = RT_NULL; + + /* check parameter */ + RT_ASSERT(rndis_class != RT_NULL); + + /*The host is configured to send and receive any of the RNDIS control messages for suitably + configuring or querying the device, to receive status indications from the device, + to reset the device, or to tear down the data and control channels*/ + usbh_rndis_eth_device.rndis_state = RNDIS_INITIALIZED; + + usbh_rndis_eth_device.keepalive_timer = rt_timer_create("keeplive", rt_rndis_dev_keepalive_timeout, + rndis_class, + RT_TICK_PER_SECOND * RNDIS_DEV_KEEPALIVE_TIMEOUT / 1000, + RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + + if (usbh_rndis_eth_device.keepalive_timer == RT_NULL) { + ret = -RT_ENOMEM; + goto __exit; + } + + rndis_class->user_data = (struct rt_device *)&usbh_rndis_eth_device; + + usbh_rndis_eth_device.rndis_recv = rt_thread_create("rndis", + (void (*)(void *parameter))rt_usbh_rndis_data_recv_entry, + rndis_class, + 1024 + 512, + 15, + 20); + + if (usbh_rndis_eth_device.rndis_recv == RT_NULL) { + ret = -RT_ENOMEM; + goto __exit; + } + + /*the LINK SPEED is 100Mbps*/ + usbh_rndis_eth_device.rndis_speed = dev_info->rndis_speed; + + eth_device_linkchange(&usbh_rndis_eth_device.parent, dev_info->up); + + for (j = 0; j < MAX_ADDR_LEN; j++) { + usbh_rndis_eth_device.dev_addr[j] = dev_info->dev_addr[j]; + } + + /* update the mac addr to netif interface */ + rt_device_control((rt_device_t)&usbh_rndis_eth_device.parent, NIOCTL_GADDR, + usbh_rndis_eth_device.parent.netif->hwaddr); + + netdev = netdev_get_by_name(RNDIS_NET_DEV_NAME); + if (netdev) { + rt_memcpy(netdev->hwaddr, recv_buf, MAX_ADDR_LEN); + } + +__exit: + if (ret == RT_EOK) { + /*This state is entered after the host has received REMOTE_NDIS_SET_CMPLT + messages from the device in response to the REMOTE_NDIS_SET_MSG + that it had sent earlier to the device with all the OIDs required to configure the device for data transfer. + When the host is in this state, apart from the control messages, + it can exchange REMOTE_NDIS_PACKET_MSG messages for network data transfer with the device on the data channel*/ + usbh_rndis_eth_device.rndis_state = RNDIS_DATA_INITIALIZED; + rt_thread_startup(usbh_rndis_eth_device.rndis_recv); + RNDIS_DEV_PRINTF("rndis dev start!\n"); + usbh_rndis_eth_device.rndis_class = rndis_class; + + } else { + RNDIS_DEV_PRINTF("rndis dev faile!\n"); + /*rndis device run error, power off the device, try it agin*/ + rt_rndis_dev_power(rndis_class, RNDIS_DEV_POWER_OFF_TIME); + } + + return ret; +} + +rt_err_t rt_rndis_stop(struct usbh_rndis *rndis_class) +{ + rt_rndis_eth_t info = RT_NULL; + + info = (rt_rndis_eth_t)rndis_class->user_data; + + if (info->rndis_recv) { + rt_thread_delete(info->rndis_recv); + info->rndis_recv = RT_NULL; + } + eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE); + usbh_rndis_eth_device.rndis_class = RT_NULL; + + /*disable the other thread etx call the rt_timer_start(rndis->keepalive_timer) cause the RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer)*/ + rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER); + if (info->keepalive_timer) { + rt_timer_stop(info->keepalive_timer); + rt_timer_delete(info->keepalive_timer); + info->keepalive_timer = RT_NULL; + } + rt_mutex_release(usbh_rndis_eth_device.rndis_mutex); + + info->rndis_state = RNDIS_BUS_UNINITIALIZED; + + RNDIS_DEV_PRINTF("rndis dev stop!\n"); + return RT_EOK; +} + +/** + * This function rndis eth device. + * + * @param intf the usb interface instance. + * + * @return the error code, RT_EOK on successfully. + */ +#ifdef RT_USING_LWIP +/* initialize the interface */ +static rt_err_t rt_rndis_eth_init(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t rt_rndis_eth_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +static rt_err_t rt_rndis_eth_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_size_t rt_rndis_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_size_t rt_rndis_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} +static rt_err_t rt_rndis_eth_control(rt_device_t dev, int cmd, void *args) +{ + rt_rndis_eth_t rndis_eth_dev = (rt_rndis_eth_t)dev; + switch (cmd) { + case NIOCTL_GADDR: + /* get mac address */ + if (args) { + rt_memcpy(args, rndis_eth_dev->dev_addr, MAX_ADDR_LEN); + } else { + return -RT_ERROR; + } + break; + + case NIOTCTL_GTXCOUNTER: + if (args) { + *(rt_uint32_t *)args = rndis_eth_dev->send_packet_counter; + } else { + return -RT_ERROR; + } + break; + + case NIOTCTL_GRXCOUNTER: + if (args) { + *(rt_uint32_t *)args = rndis_eth_dev->recv_packet_counter; + } else { + return -RT_ERROR; + } + break; + default: + break; + } + + return RT_EOK; +} + +/* ethernet device interface */ + +/* reception packet. */ +struct pbuf *rt_rndis_eth_rx(rt_device_t dev) +{ + struct pbuf *p = RT_NULL; + rt_uint32_t offset = 0; + rt_rndis_eth_t device = (rt_rndis_eth_t)dev; + rt_uint32_t recv_len = 0; + + rndis_packet_msg_t pmsg = RT_NULL; + + if (device->rx_buf_ptr == device->rx_bufferA) { + pmsg = (rndis_packet_msg_t)device->rx_bufferB; + recv_len = device->rx_lengthB; + } else { + pmsg = (rndis_packet_msg_t)device->rx_bufferA; + recv_len = device->rx_lengthA; + } + + if ((recv_len == 0) || (pmsg->DataLength == 0)) { + return RT_NULL; + } + + /* allocate buffer */ + p = pbuf_alloc(PBUF_LINK, pmsg->DataLength, PBUF_RAM); + if (p != RT_NULL) { + struct pbuf *q; + + for (q = p; q != RT_NULL; q = q->next) { + /* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */ + rt_memcpy(q->payload, + (rt_uint8_t *)((pmsg->data) + offset), + q->len); + offset += q->len; + } + } + + if (device->rx_buf_ptr == device->rx_bufferA) { + device->rx_lengthB = 0; + } else { + device->rx_lengthA = 0; + } + + return p; +} + +/* transmit packet. */ +rt_err_t rt_rndis_eth_tx(rt_device_t dev, struct pbuf *p) +{ + struct pbuf *q; + rt_uint8_t *buffer = RT_NULL; + rt_err_t result = RT_EOK; + rt_rndis_eth_t device = (rt_rndis_eth_t)dev; + rndis_packet_msg_t msg = RT_NULL; + + if (!device->parent.link_status) { + RNDIS_DEV_PRINTF("linkdown, drop pkg\r\n"); + return RT_EOK; + } + + RT_ASSERT((p->tot_len + sizeof(struct rndis_packet_msg)) < sizeof(device->tx_buffer)); + if (p->tot_len > sizeof(device->tx_buffer)) { + RNDIS_DEV_PRINTF("RNDIS MTU is:%d, but the send packet size is %d\r\n", + sizeof(device->tx_buffer), p->tot_len); + p->tot_len = sizeof(device->tx_buffer); + } + + msg = (rndis_packet_msg_t)&device->tx_buffer; + msg->MessageType = REMOTE_NDIS_PACKET_MSG; + msg->DataOffset = sizeof(struct rndis_packet_msg) - 8; + msg->DataLength = p->tot_len; + msg->OOBDataLength = 0; + msg->OOBDataOffset = 0; + msg->NumOOBDataElements = 0; + msg->PerPacketInfoOffset = 0; + msg->PerPacketInfoLength = 0; + msg->VcHandle = 0; + msg->Reserved = 0; + msg->MessageLength = sizeof(struct rndis_packet_msg) + p->tot_len; + + buffer = msg->data; + for (q = p; q != NULL; q = q->next) { + rt_memcpy(buffer, q->payload, q->len); + buffer += q->len; + } + + /* send */ + if ((msg->MessageLength & 0x3F) == 0) { + /* pad a dummy. */ + msg->MessageLength += 1; + } + + if (device->frame_debug == RT_TRUE) { + hex_data_print("rndis eth tx", (rt_uint8_t *)msg, msg->MessageLength); + } + result = rt_rndis_msg_data_send(device->rndis_class, (rt_uint8_t *)msg, msg->MessageLength); + device->send_packet_counter++; + + return result; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops rndis_device_ops = { + rt_rndis_eth_init, + rt_rndis_eth_open, + rt_rndis_eth_close, + rt_rndis_eth_read, + rt_rndis_eth_write, + rt_rndis_eth_control +} +#endif +#endif + +int usbh_rndis_eth_device_init(void) +{ + /* OUI 00-00-00, only for test. */ + usbh_rndis_eth_device.dev_addr[0] = 0xFF; + usbh_rndis_eth_device.dev_addr[1] = 0xFF; + usbh_rndis_eth_device.dev_addr[2] = 0xFF; + /* generate random MAC. */ + usbh_rndis_eth_device.dev_addr[3] = 0xFF; + usbh_rndis_eth_device.dev_addr[4] = 0xFF; + usbh_rndis_eth_device.dev_addr[5] = 0xFF; + + usbh_rndis_eth_device.rndis_mutex = rt_mutex_create("rndis", RT_IPC_FLAG_PRIO); + + if (usbh_rndis_eth_device.rndis_mutex == RT_NULL) { + RNDIS_DEV_PRINTF("Rndis mutex creat faile!\r\n"); + } + +#ifdef RT_USING_DEVICE_OPS + usbh_rndis_eth_device.parent.parent.ops = &rndis_device_ops; +#else + usbh_rndis_eth_device.parent.parent.init = rt_rndis_eth_init; + usbh_rndis_eth_device.parent.parent.open = rt_rndis_eth_open; + usbh_rndis_eth_device.parent.parent.close = rt_rndis_eth_close; + usbh_rndis_eth_device.parent.parent.read = rt_rndis_eth_read; + usbh_rndis_eth_device.parent.parent.write = rt_rndis_eth_write; + usbh_rndis_eth_device.parent.parent.control = rt_rndis_eth_control; +#endif + usbh_rndis_eth_device.parent.parent.user_data = RT_NULL; + + usbh_rndis_eth_device.parent.eth_rx = rt_rndis_eth_rx; + usbh_rndis_eth_device.parent.eth_tx = rt_rndis_eth_tx; + + /* register eth device */ + usbh_rndis_eth_device.rx_lengthA = 0; + usbh_rndis_eth_device.rx_lengthB = 0; + usbh_rndis_eth_device.rx_buf_ptr = usbh_rndis_eth_device.rx_bufferA; + usbh_rndis_eth_device.frame_debug = RT_FALSE; + + usbh_rndis_eth_device.send_packet_counter = 0; + usbh_rndis_eth_device.recv_packet_counter = 0; + + eth_device_init(&usbh_rndis_eth_device.parent, RNDIS_NET_DEV_NAME); + + eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE); + return RT_EOK; +} +INIT_APP_EXPORT(usbh_rndis_eth_device_init); + +/********************************************************************************************************* +** Function name eth_rndis_frame_debug() +** Descriptions: rndis frame print +** input parameters +** output parameters None +** Returned value: RT_EOK or RT_ERROR +*********************************************************************************************************/ +static void eth_rndis_frame_debug(int argc, char **argv) +{ + if (argc != 2) { + rt_kprintf("Please check the command you enter, it like this: rndis_debug on/off!\n"); + } else { + if (rt_strcmp(argv[1], "on") == 0) { + usbh_rndis_eth_device.frame_debug = RT_TRUE; + } else { + usbh_rndis_eth_device.frame_debug = RT_FALSE; + } + } +} + +#ifdef FINSH_USING_MSH +#include +MSH_CMD_EXPORT_ALIAS(eth_rndis_frame_debug, rndis_debug, set eth rndis frame print); +#endif /* FINSH_USING_MSH */ \ No newline at end of file