0
0
Fork 0
hgicf/utils/if_usb.c

421 lines
12 KiB
C
Raw Normal View History

2023-05-16 09:13:19 +00:00
#include <linux/version.h>
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/usb.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(3,0,0)
#include <linux/atomic.h>
#else
#include <asm/atomic.h>
#endif
#include <linux/slab.h>
#include <linux/netdevice.h>
#include "../hgic_def.h"
#include "utils.h"
2023-10-12 23:37:43 +00:00
#define HGIC_PKT_MAX_LEN (2*1024+512)
#define HGIC_TX_URB_CNT 16
#define HGIC_RX_URB_CNT 32
2023-05-16 09:13:19 +00:00
#define HGIC_USB_STATUS_STOP BIT(0)
#define HGIC_USB_STATUS_ERR BIT(1)
2023-10-12 23:37:43 +00:00
#define HGIC_USB_BUF_FLAG_USED BIT(0)
#define HGIC_USB_BUF_FLAG_RX BIT(1)
2023-05-16 09:13:19 +00:00
#define USB_TX_HEADROM 4
struct hgic_usb_buf {
struct list_head list;
2023-10-12 23:37:43 +00:00
struct hgic_usb *usbdev;
2023-05-16 09:13:19 +00:00
struct urb *urb;
2023-10-12 23:37:43 +00:00
void *data;
int flag;
2023-05-16 09:13:19 +00:00
};
struct hgic_usb {
struct usb_device *udev;
uint ep_in, ep_out;
uint ep_out_size, ep_in_size;
uint status;
struct list_head tx_freeq;
struct list_head rx_freeq;
struct list_head used;
struct semaphore tx_sema;
spinlock_t qlock;
struct hgic_bus bus;
};
static int txq_cnt = HGIC_TX_URB_CNT;
static int rxq_cnt = HGIC_RX_URB_CNT;
2023-10-12 23:37:43 +00:00
static hgic_probe probe_hdl = NULL;
static u32 max_pkt_len = HGIC_PKT_MAX_LEN;
2023-05-16 09:13:19 +00:00
static const struct usb_device_id hgic_usb_wdev_ids[] = {
2023-10-12 23:37:43 +00:00
{ USB_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_4002) },
{ USB_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_4104) },
{ USB_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_8400)},
2023-05-16 09:13:19 +00:00
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(usb, hgic_usb_wdev_ids);
static void hgic_usb_receive(struct urb *urb);
2023-10-12 23:37:43 +00:00
static void hgic_usb_cancle(struct hgic_usb *usbdev)
{
unsigned long flags;
struct hgic_usb_buf *buf, *n;
spin_lock_irqsave(&usbdev->qlock, flags);
list_for_each_entry_safe(buf, n, &usbdev->used, list) {
usb_unlink_urb(buf->urb);
}
spin_unlock_irqrestore(&usbdev->qlock, flags);
}
2023-05-16 09:13:19 +00:00
static void hgic_usb_free(struct hgic_usb *usbdev)
{
unsigned long flags;
struct hgic_usb_buf *buf, *n;
spin_lock_irqsave(&usbdev->qlock, flags);
list_for_each_entry_safe(buf, n, &usbdev->tx_freeq, list) {
list_del(&buf->list);
usb_free_urb(buf->urb);
2023-10-12 23:37:43 +00:00
if(buf->data){
hgic_err("skb is not free??\r\n");
kfree_skb(buf->data);
buf->data = NULL;
}
2023-05-16 09:13:19 +00:00
kfree(buf);
}
list_for_each_entry_safe(buf, n, &usbdev->rx_freeq, list) {
list_del(&buf->list);
2023-10-12 23:37:43 +00:00
kfree(buf->data);
2023-05-16 09:13:19 +00:00
usb_free_urb(buf->urb);
kfree(buf);
}
list_for_each_entry_safe(buf, n, &usbdev->used, list) {
usb_kill_urb(buf->urb);
list_del(&buf->list);
2023-10-12 23:37:43 +00:00
if (buf->flag & HGIC_USB_BUF_FLAG_RX) {
kfree(buf->data);
}
2023-05-16 09:13:19 +00:00
usb_free_urb(buf->urb);
kfree(buf);
}
spin_unlock_irqrestore(&usbdev->qlock, flags);
}
2023-10-12 23:37:43 +00:00
static int hgic_usb_qinit(struct hgic_usb *usb, struct list_head *q, int qsize, u8 rx)
2023-05-16 09:13:19 +00:00
{
int i = 0;
struct hgic_usb_buf *buf = NULL;
for (i = 0; i < qsize; i++) {
buf = kzalloc(sizeof(struct hgic_usb_buf), GFP_ATOMIC);
if (buf == NULL) {
2023-10-12 23:37:43 +00:00
hgic_err("alloc fail, i=%d\r\n", i);
2023-05-16 09:13:19 +00:00
break;
}
buf->usbdev = usb;
buf->urb = usb_alloc_urb(0, GFP_KERNEL);
if (buf->urb) {
2023-10-12 23:37:43 +00:00
if (rx) {
buf->data = kmalloc(max_pkt_len, GFP_KERNEL);
if (buf->data == NULL) {
kfree(buf);
hgic_err("alloc fail, len=%d\r\n", max_pkt_len);
break;
}
buf->flag |= HGIC_USB_BUF_FLAG_RX;
}
2023-05-16 09:13:19 +00:00
list_add_tail(&buf->list, q);
} else {
kfree(buf);
break;
}
}
return i;
}
2023-10-12 23:37:43 +00:00
static struct hgic_usb_buf *hgic_usb_deq(struct hgic_usb *usbdev, struct list_head *q)
2023-05-16 09:13:19 +00:00
{
struct hgic_usb_buf *buf = NULL;
unsigned long flags;
spin_lock_irqsave(&usbdev->qlock, flags);
if (!list_empty(q)) {
buf = list_first_entry(q, struct hgic_usb_buf, list);
buf->flag |= HGIC_USB_BUF_FLAG_USED;
list_del(&buf->list);
list_add_tail(&buf->list, &usbdev->used);
}
spin_unlock_irqrestore(&usbdev->qlock, flags);
return buf;
}
2023-10-12 23:37:43 +00:00
static void hgic_usb_enq(struct hgic_usb_buf *buf, struct list_head *q)
2023-05-16 09:13:19 +00:00
{
unsigned long flags;
spin_lock_irqsave(&buf->usbdev->qlock, flags);
buf->flag &= ~HGIC_USB_BUF_FLAG_USED;
list_del(&buf->list);
list_add_tail(&buf->list, q);
spin_unlock_irqrestore(&buf->usbdev->qlock, flags);
}
static int hgic_usb_submit_rx_urb(struct hgic_usb_buf *buf)
{
int ret = -1;
2023-10-12 23:37:43 +00:00
if (buf->usbdev->status & (HGIC_USB_STATUS_STOP | HGIC_USB_STATUS_ERR)) {
2023-05-16 09:13:19 +00:00
hgic_usb_enq(buf, &buf->usbdev->rx_freeq);
return -1;
}
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
usb_fill_bulk_urb(buf->urb, buf->usbdev->udev,
usb_rcvbulkpipe(buf->usbdev->udev, buf->usbdev->ep_in),
2023-10-12 23:37:43 +00:00
buf->data, max_pkt_len, hgic_usb_receive, buf);
2023-05-16 09:13:19 +00:00
ret = usb_submit_urb(buf->urb, GFP_ATOMIC);
if (ret) {
2023-10-12 23:37:43 +00:00
hgic_err("submit rx urb %p failed: %d\n", buf->urb, ret);
2023-05-16 09:13:19 +00:00
hgic_usb_enq(buf, &buf->usbdev->rx_freeq);
buf->usbdev->status |= HGIC_USB_STATUS_ERR;
2023-10-12 23:37:43 +00:00
hgic_usb_cancle(buf->usbdev);
2023-05-16 09:13:19 +00:00
return -1;
}
return 0;
}
static int hgic_usb_submit_rx_urbs(struct hgic_usb *usbdev)
{
int ret = 0;
struct hgic_usb_buf *buf = NULL;
while ((buf = hgic_usb_deq(usbdev, &usbdev->rx_freeq))) {
ret = hgic_usb_submit_rx_urb(buf);
if (ret) {
break;
}
}
return ret;
}
static void hgic_usb_receive(struct urb *urb)
{
struct hgic_usb_buf *buf = (struct hgic_usb_buf *)urb->context;
2023-10-12 23:37:43 +00:00
//hgic_enter();
if (buf->usbdev->status & HGIC_USB_STATUS_STOP) {
2023-05-16 09:13:19 +00:00
hgic_usb_enq(buf, &buf->usbdev->rx_freeq);
2023-10-12 23:37:43 +00:00
hgic_err("STOP, drop data, status=%x\r\n", buf->usbdev->status);
2023-05-16 09:13:19 +00:00
return;
}
if (urb->actual_length > 0) {
2023-10-12 23:37:43 +00:00
buf->usbdev->bus.rx_packet(buf->usbdev->bus.bus_priv, buf->data, urb->actual_length);
2023-05-16 09:13:19 +00:00
}
hgic_usb_submit_rx_urb(buf);
2023-10-12 23:37:43 +00:00
//hgic_leave();
2023-05-16 09:13:19 +00:00
}
static void hgic_usb_tx_complete(struct urb *urb)
{
struct hgic_usb_buf *buf = (struct hgic_usb_buf *)urb->context;
2023-10-12 23:37:43 +00:00
struct hgic_usb *usbdev = buf->usbdev;
usbdev->bus.tx_complete(usbdev->bus.bus_priv, (struct sk_buff *)buf->data, !urb->status);
buf->data = NULL;
hgic_usb_enq(buf, &usbdev->tx_freeq);
up(&usbdev->tx_sema);
2023-05-16 09:13:19 +00:00
}
static int hgic_usb_tx_packet(void *bus, struct sk_buff *skb)
{
int ret = 0;
int len = ALIGN(skb->len, 4);
struct hgic_usb_buf *buf = NULL;
struct hgic_usb *usbdev = container_of(bus, struct hgic_usb, bus);
2023-10-12 23:37:43 +00:00
#ifdef CONFIG_USB_ZERO_PACKET
if (IS_ALIGNED(len, usbdev->ep_out_size)) len += 4;
#endif
2023-05-16 09:13:19 +00:00
if (usbdev->status & (HGIC_USB_STATUS_STOP | HGIC_USB_STATUS_ERR)) {
ret = -EIO;
goto __fail;
}
ret = down_timeout(&usbdev->tx_sema, 1000);
2023-10-12 23:37:43 +00:00
if (ret) {
2023-05-16 09:13:19 +00:00
ret = -EIO;
2023-10-12 23:37:43 +00:00
goto __fail;
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
if (usbdev->status & (HGIC_USB_STATUS_STOP | HGIC_USB_STATUS_ERR)) {
ret = -EIO;
goto __fail;
}
2023-05-16 09:13:19 +00:00
buf = hgic_usb_deq(usbdev, &usbdev->tx_freeq);
if (buf == NULL) {
ret = -ENOMEM;
goto __fail;
}
2023-10-12 23:37:43 +00:00
buf->data = skb;
usb_fill_bulk_urb(buf->urb, usbdev->udev, usb_sndbulkpipe(usbdev->udev, usbdev->ep_out),
skb->data, len, hgic_usb_tx_complete, buf);
2023-05-16 09:13:19 +00:00
buf->urb->transfer_flags |= URB_ZERO_PACKET;
ret = usb_submit_urb(buf->urb, GFP_ATOMIC);
if (ret) {
hgic_err("usb_submit_urb failed, ret:%d\n", ret);
goto __fail;
}
return ret;
__fail:
if (buf) {
2023-10-12 23:37:43 +00:00
buf->data = NULL;
2023-05-16 09:13:19 +00:00
hgic_usb_enq(buf, &usbdev->tx_freeq);
}
usbdev->bus.tx_complete(usbdev->bus.bus_priv, skb, 0);
return ret;
}
static int hgic_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
int i = 0;
int ret = 0;
struct usb_device *udev = NULL;
struct hgic_usb *usbdev = NULL;
struct usb_host_interface *iface_desc = NULL;
struct usb_endpoint_descriptor *endpoint = NULL;
hgic_dbg("new usb card: vendor:%x, id:%x\n", id->idVendor, id->idProduct);
udev = interface_to_usbdev(intf);
iface_desc = intf->cur_altsetting;
usbdev = kzalloc(sizeof(struct hgic_usb), GFP_KERNEL);
if (!usbdev) {
return -ENOMEM;
}
usbdev->udev = udev;
2023-10-12 23:37:43 +00:00
usbdev->bus.type = HGIC_BUS_USB;
2023-05-16 09:13:19 +00:00
usbdev->bus.dev_id = id->idProduct;
2023-10-12 23:37:43 +00:00
usbdev->bus.drv_tx_headroom = USB_TX_HEADROM;
usbdev->bus.tx_packet = hgic_usb_tx_packet;
usbdev->bus.bootdl_pktlen = 2048;
usbdev->bus.bootdl_cksum = HGIC_BUS_BOOTDL_CHECK_0XFD;
usbdev->bus.probe = probe_hdl;
//usbdev->status = HGIC_USB_STATUS_STOP;
2023-05-16 09:13:19 +00:00
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(endpoint)) {
usbdev->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
usbdev->ep_in = usb_endpoint_num(endpoint);
hgic_dbg("IN BULK: ep_in_size:%x, ep_in:%x\n", usbdev->ep_in_size, usbdev->ep_in);
} else if (usb_endpoint_is_bulk_out(endpoint)) {
usbdev->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
usbdev->ep_out = usb_endpoint_num(endpoint);
hgic_dbg("OUT BULK: ep_out_size:%x, ep_out:%x\n", usbdev->ep_out_size, usbdev->ep_out);
}
}
usbdev->bus.blk_size = usbdev->ep_out_size;
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
spin_lock_init(&usbdev->qlock);
INIT_LIST_HEAD(&usbdev->tx_freeq);
INIT_LIST_HEAD(&usbdev->rx_freeq);
INIT_LIST_HEAD(&usbdev->used);
2023-10-12 23:37:43 +00:00
ret = hgic_usb_qinit(usbdev, &usbdev->tx_freeq, txq_cnt, 0);
2023-05-16 09:13:19 +00:00
sema_init(&usbdev->tx_sema, ret);
hgic_dbg("usb txq:%d\r\n", ret);
2023-10-12 23:37:43 +00:00
ret = hgic_usb_qinit(usbdev, &usbdev->rx_freeq, rxq_cnt, 1);
2023-05-16 09:13:19 +00:00
hgic_dbg("usb rxq:%d\r\n", ret);
2023-10-12 23:37:43 +00:00
usbdev->bus.probe(&udev->dev, &usbdev->bus);
2023-05-16 09:13:19 +00:00
if (!usbdev->bus.bus_priv) {
ret = -ENOMEM;
goto __failed;
}
2023-10-12 23:37:43 +00:00
usb_get_dev(udev);
usb_set_intfdata(intf, usbdev);
//usbdev->status &= ~HGIC_USB_STATUS_STOP;
2023-05-16 09:13:19 +00:00
ret = hgic_usb_submit_rx_urbs(usbdev);
if (ret) {
goto __failed;
}
2023-10-12 23:37:43 +00:00
if (usbdev->bus.probe_post) {
usbdev->bus.probe_post(usbdev->bus.bus_priv);
}
2023-05-16 09:13:19 +00:00
return ret;
__failed:
2023-10-12 23:37:43 +00:00
if (usbdev->bus.remove) {
usbdev->bus.remove(usbdev->bus.bus_priv);
}
2023-05-16 09:13:19 +00:00
hgic_usb_free(usbdev);
kfree(usbdev);
return -1;
}
static void hgic_usb_disconnect(struct usb_interface *intf)
{
struct hgic_usb *usbdev = usb_get_intfdata(intf);
2023-10-12 23:37:43 +00:00
hgic_dbg("Enter\n");
2023-05-16 09:13:19 +00:00
if (usbdev) {
usbdev->status |= HGIC_USB_STATUS_STOP;
2023-10-12 23:37:43 +00:00
up(&usbdev->tx_sema);
if (usbdev->bus.remove) {
usbdev->bus.remove(usbdev->bus.bus_priv);
}
2023-05-16 09:13:19 +00:00
hgic_usb_free(usbdev);
kfree(usbdev);
usb_set_intfdata(intf, NULL);
}
2023-10-12 23:37:43 +00:00
hgic_dbg("Leave\n");
2023-05-16 09:13:19 +00:00
}
static struct usb_driver hgic_usb_driver = {
.name = KBUILD_MODNAME,
.probe = hgic_usb_probe,
.disconnect = hgic_usb_disconnect,
.id_table = hgic_usb_wdev_ids,
.suspend = NULL,
.resume = NULL,
.supports_autosuspend = 1,
};
2023-10-12 23:37:43 +00:00
int __init hgic_usb_init(hgic_probe probe, u32 max_pkt)
2023-05-16 09:13:19 +00:00
{
int ret = 0;
2023-10-12 23:37:43 +00:00
hgic_dbg("Enter, max_pkt_len = %d\n", max_pkt_len);
probe_hdl = probe;
if(max_pkt > HGIC_PKT_MAX_LEN){
max_pkt_len = max_pkt;
}
2023-05-16 09:13:19 +00:00
ret = usb_register(&hgic_usb_driver);
if (ret) {
hgic_err("driver register failed: %d\n", ret);
}
hgic_dbg("Leave\n");
return ret;
}
void __exit hgic_usb_exit(void)
{
hgic_dbg("Enter\n");
usb_deregister(&hgic_usb_driver);
hgic_dbg("Leave\n");
}