Files
刘可亮 3e10f578d3 v1.2.2
2025-10-21 13:59:50 +08:00

219 lines
5.9 KiB
C

/*
* Copyright (c) 2025, ArtInChip
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
// #include "usbh_serial.h"
#define DEV_FORMAT "/dev/ttyUSB%d"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_buf[USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 5
struct usbh_serial {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
uint8_t intf;
uint8_t minor;
void *user_data;
};
static struct usbh_serial g_serial_class[CONFIG_USBHOST_MAX_SERIAL_CLASS];
static uint32_t g_devinuse = 0;
__WEAK void usbh_serial_run(struct usbh_serial *serial_class)
{
(void)serial_class;
}
__WEAK void usbh_serial_stop(struct usbh_serial *serial_class)
{
(void)serial_class;
}
static struct usbh_serial *usbh_serial_class_alloc(void)
{
uint8_t devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno++) {
if ((g_devinuse & (1U << devno)) == 0) {
g_devinuse |= (1U << devno);
memset(&g_serial_class[devno], 0, sizeof(struct usbh_serial));
g_serial_class[devno].minor = devno;
return &g_serial_class[devno];
}
}
return NULL;
}
static void usbh_serial_class_free(struct usbh_serial *serial_class)
{
uint8_t devno = serial_class->minor;
if (devno < 32) {
g_devinuse &= ~(1U << devno);
}
memset(serial_class, 0, sizeof(struct usbh_serial));
}
static int usbh_serial_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
struct usbh_serial *serial_class = usbh_serial_class_alloc();
if (serial_class == NULL) {
USB_LOG_ERR("Fail to alloc serial_class\r\n");
return -USB_ERR_NOMEM;
}
serial_class->hport = hport;
serial_class->intf = intf;
hport->config.intf[intf].priv = serial_class;
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(serial_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(serial_class->bulkout, ep_desc);
}
}
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, serial_class->minor);
USB_LOG_INFO("Register Serial Class:%s\r\n", hport->config.intf[intf].devname);
usbh_serial_run(serial_class);
return ret;
}
static int usbh_serial_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_serial *serial_class = (struct usbh_serial *)hport->config.intf[intf].priv;
if (serial_class) {
if (serial_class->bulkin) {
usbh_kill_urb(&serial_class->bulkin_urb);
}
if (serial_class->bulkout) {
usbh_kill_urb(&serial_class->bulkout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister Serial Class:%s\r\n", hport->config.intf[intf].devname);
usbh_serial_stop(serial_class);
}
usbh_serial_class_free(serial_class);
}
return ret;
}
int usbh_serial_bulk_in_transfer(struct usbh_serial *serial_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &serial_class->bulkin_urb;
usbh_bulk_urb_fill(urb, serial_class->hport, serial_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
int usbh_serial_bulk_out_transfer(struct usbh_serial *serial_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &serial_class->bulkout_urb;
usbh_bulk_urb_fill(urb, serial_class->hport, serial_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
//ttyusb 0 AT
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX char serial_buffer[512];
int cmd_ttyusb_debug(int argc, char *argv[])
{
int ret;
struct usbh_serial *serial_class;
int len = 0;
char dev_name[20] = {0};
if (argc != 3) {
printf("ttyusb [NO] [AT]\n");
return -1;
}
snprintf(dev_name, 20, "/dev/ttyUSB%s", argv[1]);
while ((serial_class = (struct usbh_serial *)usbh_find_class_instance(dev_name)) == NULL) {
printf("Can't find name %s\n", dev_name);
return -1;
}
memset(serial_buffer, 0, 512);
strncpy(serial_buffer, argv[2], 511);
len = strlen(serial_buffer);
serial_buffer[len++] = '\r';
serial_buffer[len++] = '\n';
printf("%s send: %s\n", dev_name, serial_buffer);
ret = usbh_serial_bulk_out_transfer(serial_class, (uint8_t *)serial_buffer, len, 100);
if (ret < 0) {
USB_LOG_RAW("bulk out error,ret:%d\r\n", ret);
return -1;
} else {
USB_LOG_RAW("send over:%d\r\n", serial_class->bulkout_urb.actual_length);
}
ret = usbh_serial_bulk_in_transfer(serial_class, (uint8_t *)serial_buffer, 512, 100);
if (ret < 0) {
USB_LOG_RAW("bulk in error,ret:%d\r\n", ret);
return -1;
} else {
}
printf("%s receive: %s\n", dev_name, serial_buffer);
return 0;
}
MSH_CMD_EXPORT_ALIAS(cmd_ttyusb_debug, ttyusb, ttycmd);
const struct usbh_class_driver serial_class_driver = {
.driver_name = "serial",
.connect = usbh_serial_connect,
.disconnect = usbh_serial_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info serial_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,//USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0,
.protocol = 0,
.vid = 0,
.pid = 0,
.class_driver = &serial_class_driver
};