mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-17 09:38:55 +00:00
v1.2.2
This commit is contained in:
267
packages/third-party/cherryusb/port/aic/rtt_driver_port/rtt_usbh_hid.c
vendored
Normal file
267
packages/third-party/cherryusb/port/aic/rtt_driver_port/rtt_usbh_hid.c
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (c) 2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: artinchip
|
||||
*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_hid.h"
|
||||
#include "aic_osal.h"
|
||||
|
||||
#define AICUSB_HID_POOL_SIZE 5
|
||||
#define AICUSB_HID_PROTOCOL(id, pro_name) {.pro_id = id, .name = (pro_name),}
|
||||
|
||||
struct hid_protocol {
|
||||
rt_list_t list;
|
||||
int pro_id;
|
||||
char name[16];
|
||||
void *data; // todo: hash table for muticast device
|
||||
};
|
||||
|
||||
struct hid_device {
|
||||
struct hid_protocol *pro;
|
||||
struct rt_device parent;
|
||||
};
|
||||
|
||||
enum hid_register_type {
|
||||
HID_REGISTER,
|
||||
HID_UNREGISTER,
|
||||
};
|
||||
|
||||
static rt_list_t hid_protocal_list;
|
||||
static struct hid_device hid_dev_pool[AICUSB_HID_POOL_SIZE];
|
||||
|
||||
struct hid_protocol gt_hid_proocol[] = {
|
||||
AICUSB_HID_PROTOCOL(0, "keyboard0"),
|
||||
AICUSB_HID_PROTOCOL(1, "keyboard1"),
|
||||
AICUSB_HID_PROTOCOL(2, "mouse"),
|
||||
};
|
||||
|
||||
|
||||
void aicusbh_hid_hotplug_irq(char *name, int32_t hotplug);
|
||||
|
||||
static struct hid_device *get_hid_dev_from_pool()
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < AICUSB_HID_POOL_SIZE; i++) {
|
||||
if (!hid_dev_pool[i].pro)
|
||||
return &hid_dev_pool[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void release_hid_dev_to_pool(struct hid_device *hid_dev)
|
||||
{
|
||||
memset(hid_dev, 0, sizeof(struct hid_device));
|
||||
}
|
||||
|
||||
static int aicusbh_hid_protocol_register(struct hid_protocol *pro)
|
||||
{
|
||||
RT_ASSERT(pro != RT_NULL);
|
||||
|
||||
/* insert class driver into driver list */
|
||||
rt_list_insert_after(&hid_protocal_list, &(pro->list));
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct hid_protocol *aicusbh_hid_protocol_find(int pro_id)
|
||||
{
|
||||
struct rt_list_node *node;
|
||||
struct hid_protocol *pro;
|
||||
|
||||
/* try to find protocal object */
|
||||
for (node = hid_protocal_list.next; node != &hid_protocal_list; node = node->next)
|
||||
{
|
||||
pro = (struct hid_protocol *)rt_list_entry(node, struct hid_protocol, list);
|
||||
if (pro->pro_id == pro_id)
|
||||
return pro;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static rt_err_t aicusbh_hid_open(rt_device_t dev, rt_uint16_t flag)
|
||||
{
|
||||
struct usbh_hid *hid_class = (struct usbh_hid *)dev->user_data;
|
||||
|
||||
usbh_hubport_enumerate_wait(hid_class->hport);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_t aicusbh_hid_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t len)
|
||||
{
|
||||
struct usbh_hid *hid_class = (struct usbh_hid *)dev->user_data;
|
||||
struct hid_protocol *pro;
|
||||
|
||||
pro = aicusbh_hid_protocol_find(hid_class->protocol);
|
||||
if (!pro) {
|
||||
USB_LOG_ERR("Can't support such HID protocol NO.%d\n", hid_class->protocol);
|
||||
return -RT_EEMPTY;
|
||||
}
|
||||
|
||||
if (len != hid_class->intin->wMaxPacketSize) {
|
||||
USB_LOG_ERR("HID device[%s] read length must be %dbytes\n", pro->name, hid_class->intin->wMaxPacketSize);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin,
|
||||
buf, len,
|
||||
USB_OSAL_WAITING_FOREVER, NULL, hid_class);
|
||||
if (usbh_submit_urb(&hid_class->intin_urb) != 0) {
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static rt_err_t aicusbh_hid_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
struct usbh_hid *hid_class = (struct usbh_hid *)dev->user_data;
|
||||
int ret = RT_EOK;
|
||||
switch (cmd) {
|
||||
case 0:
|
||||
*((uint16_t *)args) = hid_class->intin->wMaxPacketSize;
|
||||
break;
|
||||
case 1:
|
||||
*((uint8_t *)args) = hid_class->bInterval;
|
||||
break;
|
||||
default:
|
||||
ret = -RT_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
static struct rt_device_ops aic_usbh_hid_ops = {
|
||||
.open = aicusbh_hid_open,
|
||||
.read = aicusbh_hid_read,
|
||||
.control = aicusbh_hid_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int aicusbh_hid_device_register(struct hid_protocol *pro, struct usbh_hid *hid_class)
|
||||
{
|
||||
int result;
|
||||
rt_device_t device;
|
||||
struct hid_device *hid_dev;
|
||||
|
||||
hid_dev = get_hid_dev_from_pool();
|
||||
if (!hid_dev) {
|
||||
USB_LOG_ERR("Can't get hid deveice from hid device pool\n");
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
hid_dev->pro = pro;
|
||||
pro->data = hid_dev;
|
||||
|
||||
device = &hid_dev->parent;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &aic_usbh_hid_ops;
|
||||
#else
|
||||
device->init = RT_NULL;
|
||||
device->open = aicusbh_hid_open;
|
||||
device->close = RT_NULL;
|
||||
device->read = aicusbh_hid_read;
|
||||
device->write = RT_NULL;
|
||||
device->control = aicusbh_hid_control;
|
||||
#endif
|
||||
|
||||
device->type = RT_Device_Class_Char;
|
||||
device->rx_indicate = RT_NULL;
|
||||
device->tx_complete = RT_NULL;
|
||||
device->user_data = hid_class;
|
||||
|
||||
result = rt_device_register(device, pro->name, RT_DEVICE_FLAG_RDONLY);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
USB_LOG_ERR("HID device register err code: %d\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("HID device[%s] register success\n", pro->name);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int aicusbh_hid_device_unregister(struct hid_protocol *pro)
|
||||
{
|
||||
struct hid_device *hid_dev = (struct hid_device *)pro->data;
|
||||
rt_device_t device = &hid_dev->parent;
|
||||
|
||||
pro->data = NULL;
|
||||
rt_device_unregister(device);
|
||||
release_hid_dev_to_pool(hid_dev);
|
||||
|
||||
USB_LOG_INFO("HID device[%s] unregister success\n", pro->name);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void do_hid_register(struct usbh_hid *hid_class)
|
||||
{
|
||||
struct hid_protocol *pro;
|
||||
|
||||
pro = aicusbh_hid_protocol_find(hid_class->protocol);
|
||||
if (!pro) {
|
||||
USB_LOG_ERR("Can't support such HID protocol NO.%d\n", hid_class->protocol);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't support muticast device */
|
||||
if (pro->data) {
|
||||
USB_LOG_WRN("%s has been used, ignoring latest device\n", pro->name);
|
||||
return;
|
||||
}
|
||||
|
||||
aicusbh_hid_device_register(pro, hid_class);
|
||||
aicusbh_hid_hotplug_irq(pro->name, true);
|
||||
}
|
||||
|
||||
static void do_hid_unregister(struct usbh_hid *hid_class)
|
||||
{
|
||||
struct hid_protocol *pro;
|
||||
pro = aicusbh_hid_protocol_find(hid_class->protocol);
|
||||
if (!pro) {
|
||||
USB_LOG_ERR("Can't find HID protocol NO.%d\n", hid_class->protocol);
|
||||
return;
|
||||
}
|
||||
|
||||
aicusbh_hid_device_unregister(pro);
|
||||
aicusbh_hid_hotplug_irq(pro->name, false);
|
||||
}
|
||||
|
||||
__WEAK void aicusbh_hid_hotplug_irq(char *name, int32_t hotplug)
|
||||
{
|
||||
}
|
||||
|
||||
void usbh_hid_run(struct usbh_hid *hid_class)
|
||||
{
|
||||
do_hid_register(hid_class);
|
||||
}
|
||||
|
||||
void usbh_hid_stop(struct usbh_hid *hid_class)
|
||||
{
|
||||
do_hid_unregister(hid_class);
|
||||
}
|
||||
|
||||
static int aicusb_hid_driver_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
rt_list_init(&hid_protocal_list);
|
||||
|
||||
for (i = 0; i < (sizeof(gt_hid_proocol) / sizeof(gt_hid_proocol[0])); i++)
|
||||
aicusbh_hid_protocol_register(>_hid_proocol[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_ENV_EXPORT(aicusb_hid_driver_init);
|
||||
@@ -12,6 +12,11 @@
|
||||
#include <rtthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(KERNEL_RTTHREAD) && defined(LPKG_CHERRYUSB_DEVICE_PLUG_CHECK)
|
||||
#include <rtdevice.h>
|
||||
#include "aic_hal.h"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
#ifndef __UNALIGNED_UINT32_WRITE
|
||||
#pragma GCC diagnostic push
|
||||
@@ -712,7 +717,9 @@ int usb_dc_init(void)
|
||||
tmpreg = readl(&AIC_UDC_REG->usbdevfunc);
|
||||
tmpreg &= ~USBDEVFUNC_SFTDISCON;
|
||||
writel(tmpreg, &AIC_UDC_REG->usbdevfunc);
|
||||
|
||||
#if defined(KERNEL_RTTHREAD) && defined(LPKG_CHERRYUSB_DEVICE_PLUG_CHECK)
|
||||
ret = usbd_plug_irq_init();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1739,3 +1746,40 @@ void USBD_IRQHandler(void)
|
||||
writel(INT_RESUME, &AIC_UDC_REG->usbintsts);
|
||||
}
|
||||
}
|
||||
|
||||
/*add usb plug/unplug check function*/
|
||||
#if defined(KERNEL_RTTHREAD) && defined(LPKG_CHERRYUSB_DEVICE_PLUG_CHECK)
|
||||
void usb_plug_irq(void *args)
|
||||
{
|
||||
unsigned int ret;
|
||||
int pin = *((int *)(args));
|
||||
|
||||
hal_gpio_get_value(GPIO_GROUP(pin), GPIO_GROUP_PIN(pin), &ret);
|
||||
if (ret) {
|
||||
usbd_event_connect_handler();
|
||||
} else {
|
||||
usbd_event_disconnect_handler();
|
||||
}
|
||||
}
|
||||
int usbd_plug_irq_init(void)
|
||||
{
|
||||
static rt_base_t pin = 0;
|
||||
unsigned int g, p;
|
||||
|
||||
pin = rt_pin_get(LPKG_PLUG_CHECK_GPIO);
|
||||
if (pin < 0) {
|
||||
USB_LOG_ERR("get id gpio err.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g = GPIO_GROUP(pin);
|
||||
p = GPIO_GROUP_PIN(pin);
|
||||
hal_gpio_set_debounce(g, p, 0xFFF);
|
||||
rt_pin_mode(pin, PIN_MODE_INPUT);
|
||||
|
||||
rt_pin_attach_irq(pin, PIN_IRQ_MODE_RISING_FALLING, usb_plug_irq, &pin);
|
||||
rt_pin_irq_enable(pin, 1);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user