2021-01-22

这个代码段展示了Linux内核中的一个USB串口驱动程序,用于处理USB ACM设备(如调制解调器)的数据传输。驱动程序包含了打开、关闭、读写操作的实现,以及挂起和恢复的处理。它使用工作队列和任务let来处理读取和写入的数据,并管理 urb (USB请求块) 和缓冲区。驱动还实现了设备的挂起和唤醒功能,以及节流和解节流机制。
摘要由CSDN通过智能技术生成

/*
 * USB Serial Converter Generic functions
 *
 * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
 *
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU General Public License version
 *    2 as published by the Free Software Foundation.
 *
 * Copyright (C) 2009 - 2010 Liu Xiang-Shuang (13361295927@qq.com)
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <asm/uaccess.h>

//
#define ACM_NW  16
#define ACM_NR  16


struct acm_rb {
    struct list_head    list;
    int            size;
    unsigned char        *base;
    dma_addr_t        dma;
};

struct acm_ru {
    struct list_head    list;
    struct acm_rb        *buffer;
    struct urb        *urb;
    struct acm        *instance;
};

struct acm {
    struct usb_device *dev;                /* the corresponding usb device */
    struct usb_interface *data;            /* data interface */
    struct tty_struct *tty;                /* the corresponding tty */
    struct acm_rb wb[ACM_NW];
    struct acm_ru wu[ACM_NW];
    struct list_head spare_write_urbs;
    struct list_head spare_write_bufs;
    struct acm_ru ru[ACM_NR];
    struct acm_rb rb[ACM_NR];
    int rx_buflimit;
    int rx_endpoint;
    spinlock_t read_lock;
    struct list_head spare_read_urbs;
    struct list_head spare_read_bufs;
    struct list_head filled_read_bufs;
    int write_ready;                /* write urb is not running */
    spinlock_t write_lock;
    struct mutex mutex;
    //struct usb_cdc_line_coding line;        /* bits, stop, parity */
    struct work_struct work;            /* work queue entry for line discipline waking up */
    struct tasklet_struct urb_task;                 /* rx processing */
    spinlock_t throttle_lock;            /* synchronize throtteling and read callback */
    unsigned int writesize;                /* max packet size for the output bulk endpoint */
    unsigned int readsize,ctrlsize;            /* buffer sizes for freeing */
    unsigned int used;                /* someone has this acm's device open */
    unsigned char throttle;                /* throttled by tty layer */
    unsigned char clocal;                /* termios CLOCAL */
    unsigned int susp_count;            /* number of suspended interfaces */
    unsigned int skip;
};

#define PORT_READY(acm)    (acm && acm->dev && acm->used)

//
#define DRIVER_VERSION    "v0.1"
#define DRIVER_AUTHOR    "Liu-xs"
#define DRIVER_DESC    "TD modem usb serial driver"

//extern void userial_auto_suspend(void);
extern void userial_auto_lock_suspend(void);


static int debug;
static int wb_count_test = ACM_NW;


#define MNAME "[USB High-speed serial]"

static int usb_serial_highspeed_probe(struct usb_serial_port *port);
static void usb_serial_highspeed_read_bulk_callback(struct urb *urb);


static int generic_probe(struct usb_interface *interface,
             const struct usb_device_id *id);
static int generic_suspend(struct usb_interface *intf, pm_message_t message);
static int generic_resume(struct usb_interface *intf);

static __u16 vendor  = 0x1ab7;
static __u16 product = 0x6000;

module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified USB idVendor");

module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified USB idProduct");

static struct usb_device_id hs_device_ids[2]; /* Initially all zeroes. */

/* we want to look at all devices, as the vendor/product id can change
 * depending on the command line argument */
static struct usb_device_id hs_serial_ids[] = {
    { USB_DEVICE(0x1ab7, 0x6000) },
    {}
};

static int generic_probe(struct usb_interface *interface,
                   const struct usb_device_id *id)
{
    const struct usb_device_id *id_pattern;

    id_pattern = usb_match_id(interface, hs_device_ids);
    if (id_pattern != NULL)
        return usb_serial_probe(interface, id);
    return -ENODEV;
}

static int generic_suspend(struct usb_interface *intf, pm_message_t message)
{
    struct usb_serial *serial = usb_get_intfdata(intf);
    //printk("%s\n",__FUNCTION__);
    if(serial->type && serial->type->suspend)
        return serial->type->suspend(serial, message);
    return 0;
}

static int generic_resume(struct usb_interface *intf)
{
    struct usb_serial *serial = usb_get_intfdata(intf);
    //printk("%s\n",__FUNCTION__);
    if(serial->type && serial->type->resume)
        return serial->type->resume(serial);
    return 0;
}

void usb_serial_highspeed_stop_data_traffic(struct acm *acm)
{
    int i;

    dbg("%s - !!!!", __FUNCTION__ );
    
    tasklet_disable(&acm->urb_task);

    for (i = 0; i < acm->rx_buflimit; i++)
        usb_kill_urb(acm->ru[i].urb);
    for (i = 0; i < ACM_NW; i++)
        usb_kill_urb(acm->wu[i].urb);

    INIT_LIST_HEAD(&acm->filled_read_bufs);
    INIT_LIST_HEAD(&acm->spare_read_bufs);

    tasklet_enable(&acm->urb_task);

    cancel_work_sync(&acm->work);
}


static int usb_serial_highspeed_open (struct usb_serial_port *port, struct file *filp)
{
    struct usb_serial *serial = port->serial;
    int result = 0;
    unsigned long flags;
    struct acm *acm = usb_get_serial_port_data(port);
    int i;

    dbg("%s - port %d", __FUNCTION__, port->number);

    /* force low_latency on so that our tty_push actually forces the data through, 
       otherwise it is scheduled, and with high data rates (like with OHCI) data
       can get lost. */
    if (port->tty)
        port->tty->low_latency = 1;
    else
        pr_err(" tty is NULL!");

    /* clear the throttle flags */
    spin_lock_irqsave(&port->lock, flags);
    acm->throttle = 0;
    spin_unlock_irqrestore(&port->lock, flags);

    /* if we have a bulk endpoint, start reading from it */
    if (serial->num_bulk_in == 0) {
        pr_err("++++++ num_bulk_in  = 0 \n");
        return result;
    }

    mutex_lock(&acm->mutex);

    if (acm->used++) {
        return result;
        }

    acm->tty = port->tty;
    INIT_LIST_HEAD(&acm->spare_read_urbs);
    INIT_LIST_HEAD(&acm->spare_read_bufs);
    INIT_LIST_HEAD(&acm->filled_read_bufs);

    INIT_LIST_HEAD(&acm->spare_write_urbs);
    INIT_LIST_HEAD(&acm->spare_write_bufs);

    for (i = 0; i < acm->rx_buflimit; i++) {
        list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
    }
    for (i = 0; i < acm->rx_buflimit; i++) {
        list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
    }

    for (i = 0; i < ACM_NW; i++) {
        list_add(&(acm->wu[i].list), &acm->spare_write_urbs);
    }
    for (i = 0; i < ACM_NW; i++) {
        list_add(&(acm->wb[i].list), &acm->spare_write_bufs);
    }

    tasklet_schedule(&acm->urb_task);

    mutex_unlock(&acm->mutex);

    return result;
}

static void usb_serial_highspeed_cleanup (struct usb_serial_port *port)
{
    struct usb_serial *serial = port->serial;
    struct acm * acm =usb_get_serial_port_data(port);

    dbg("%s - port %d", __FUNCTION__, port->number);

    if (!acm || !acm->used)
        return;

    if (!--acm->used) {
        if (serial->dev) {
            usb_serial_highspeed_stop_data_traffic(acm);
        }
    }
}

int usb_serial_highspeed_suspend(struct usb_serial *serial, pm_message_t message)
{
    struct usb_serial_port *port;
    int i, c = 0;

#ifdef CONFIG_PM
    /*
     * If this is an autoresume, don't submit URBs.
     * They will be submitted in the open function instead.
     */
    if (serial->dev->auto_pm)
        return 0;
#endif
    for (i = 0; i < serial->num_ports; i++) {
        struct acm *acm ;
        port = serial->port[i];
        acm = usb_get_serial_port_data(port);

        if (acm->susp_count++)
            continue;
        pr_err("usb_serial_highspeed_suspend !\n");
        /*
        we treat opened interfaces differently,
        we must guard against open
        */
        mutex_lock(&acm->mutex);

        if (acm->used)
            usb_serial_highspeed_stop_data_traffic(acm);

        mutex_unlock(&acm->mutex);
    }

    return c ? -EIO : 0;
}

int usb_serial_highspeed_resume(struct usb_serial *serial)
{
    struct usb_serial_port *port;
    int i, j,c = 0;

#ifdef CONFIG_PM
    /*
     * If this is an autoresume, don't submit URBs.
     * They will be submitted in the open function instead.
     */
    if (serial->dev->auto_pm)
        return 0;
#endif

    for (i = 0; i < serial->num_ports; i++) {
        struct acm *acm ;
        port = serial->port[i];
        acm = usb_get_serial_port_data(port);

        if (--acm->susp_count)
            continue;
        pr_err("usb_serial_highspeed_resume !\n");
        mutex_lock(&acm->mutex);
        if (acm->used) {
            for (j = 0; j < acm->rx_buflimit; j++) {
                list_add(&(acm->rb[j].list), &acm->spare_read_bufs);
            }
            acm->skip = 0;
            tasklet_schedule(&acm->urb_task);
        }
        mutex_unlock(&acm->mutex);
    }

    return c ? -EIO : 0;
}

void usb_serial_highspeed_close (struct usb_serial_port *port, struct file * filp)
{
    pr_err("%s - port %d", __FUNCTION__, port->number);
    usb_serial_highspeed_cleanup (port);
}

/* Little helper: write buffers free */
static void acm_write_buffers_free(struct acm *acm)
{
    int i;

    for (i = 0; i < ACM_NW; i++) {
        struct acm_ru *wu = &(acm->wu[i]);
        struct acm_rb *wb = &(acm->wb[i]);

        usb_free_urb(wu->urb);
        usb_buffer_free(acm->dev, acm->writesize, wb->base, wb->dma);
    }
}

static int acm_wb_is_avail(struct acm *acm)
{
    int n = 0;
    struct list_head *p;

    spin_lock(&acm->write_lock);
    list_for_each(p, &acm->spare_write_urbs)n++;
    spin_unlock(&acm->write_lock);

    return n;
}

/* data interface wrote those outgoing bytes */
static void acm_write_bulk(struct urb *urb)
{
    struct acm_rb *buf;
    struct acm_ru *wu = urb->context;
    struct acm *acm = wu->instance;
    int status = urb->status;
    
    if (!PORT_READY(acm))
        return;

    if (status)
        //dev_dbg(&acm->data->dev, "bulk tx status %d\n", status);
        pr_err(" !!!bulk tx status : %d\n", status);
    if (acm->susp_count)
        pr_err(" acm_write_bulk :after suspend \n");

#ifdef CONFIG_ANDROID_POWER
    userial_auto_lock_suspend();
#endif

    buf = wu->buffer;
    spin_lock(&acm->write_lock);
    list_add_tail(&wu->list, &acm->spare_write_urbs);
    list_add_tail(&buf->list, &acm->spare_write_bufs);
    wb_count_test ++;
    spin_unlock(&acm->write_lock);
    if (likely(status == 0)) {
        schedule_work(&acm->work);
        acm->write_ready = 1;
        //pr_err(" !!!bulk tx actual_length : %d\n", urb->actual_length);
    } else {
        /* nevertheless the tasklet must be kicked unconditionally
        so the queue cannot dry up */
        if(acm_wb_is_avail( acm)<ACM_NW)
            acm->write_ready = 0;
        else
            schedule_work(&acm->work);
    }

}

static void acm_softint(struct work_struct *work)
{
    struct acm *acm = container_of(work, struct acm, work);
    dbg("Entering acm_softint.");
    
    if (!PORT_READY(acm))
        return;
    if(acm->write_ready)
        tty_wakeup(acm->tty);
}
void show_usb_log (int on)
{
    debug = on;
}

int usb_serial_highspeed_write(struct usb_serial_port *port, const unsigned char *buf, int count)
{
    struct acm * acm =usb_get_serial_port_data(port);
    int stat = 0;
    unsigned long flags;
    struct acm_rb *wbuf;
    struct acm_ru *wu;

    dbg("%s - port %d", __FUNCTION__, port->number);

    if (count == 0) {
        dbg("%s - write request of 0 bytes", __FUNCTION__);
        return (0);
    }
    while(count>0) {
        int writesize;
        spin_lock_irqsave(&acm->write_lock, flags);
        if(list_empty(&acm->spare_write_bufs) || list_empty(&acm->spare_write_urbs)){
            spin_unlock_irqrestore(&acm->write_lock, flags);
            break;
        }
        wu = list_entry(acm->spare_write_urbs.next,
                 struct acm_ru, list);
        list_del(&wu->list);

        wb_count_test --;

        wbuf = list_entry(acm->spare_write_bufs.next,
                 struct acm_rb, list);
        list_del(&wbuf->list);
        spin_unlock_irqrestore(&acm->write_lock, flags);

        writesize = (count > acm->writesize) ? acm->writesize : count;
        memcpy(wbuf->base, buf, writesize);
        wu->buffer = wbuf;        
        wu->urb->transfer_buffer = wbuf->base;
        wu->urb->transfer_buffer_length = writesize;
        wu->urb->transfer_dma = wbuf->dma;
        wu->urb->context = wu;

        if (usb_submit_urb(wu->urb, GFP_ATOMIC) < 0) {
            spin_lock_irqsave(&acm->write_lock, flags);
            list_add(&wbuf->list, &acm->spare_write_bufs);
            list_add(&wu->list, &acm->spare_write_urbs);
            wb_count_test ++;
            spin_unlock_irqrestore(&acm->write_lock, flags);
            break;
        }
        stat += writesize;
        buf  += writesize;
        count -= writesize;
//        acm->write_ready = 0;
    }
    if(debug)
    pr_err(" !!!serial_write tx count : %d; stat : %d; wb_count_test: %d\n", count, stat, wb_count_test);

    return stat;


    /* no bulk out, so return 0 bytes written */
    return 0;
}

int usb_serial_highspeed_write_room (struct usb_serial_port *port)
{
    struct acm * acm =usb_get_serial_port_data(port);

    dbg("%s - port %d", __FUNCTION__, port->number);

    if (!PORT_READY(acm))
        return -EINVAL;
    /*
     * Do not let the line discipline to know that we have a reserve,
     * or it might get too enthusiastic.
     */
    return (acm->write_ready && acm_wb_is_avail(acm)) ? acm_wb_is_avail(acm)*acm->writesize : 0;
}

int usb_serial_highspeed_chars_in_buffer (struct usb_serial_port *port)
{
    struct acm * acm =usb_get_serial_port_data(port);

    dbg("%s - port %d", __FUNCTION__, port->number);

    if (!PORT_READY(acm))
        return -EINVAL;
    /*
     * This is inaccurate (overcounts), but it works.
     */
    return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
}

static char test[64];
static int testcount= 0;
static int recvcount= 0;
void usb_serial_highspeed_rx_tasklet(unsigned long _acm)
{
    struct acm *acm = (void *)_acm;
    struct acm_rb *buf;
    struct tty_struct *tty = acm->tty;
    struct acm_ru *rcv;
    unsigned long flags;
    unsigned char throttled;

    static int zcount = 0;
    static int ncount= 0;

    dbg("Entering usb_serial_highspeed_rx_tasklet");

    if (!PORT_READY(acm)){
        pr_err("usb_serial_highspeed_rx_tasklet : PORT_READY =0 \n");
        return;
        }

    spin_lock_irqsave(&acm->throttle_lock, flags);
    throttled = acm->throttle;
    spin_unlock_irqrestore(&acm->throttle_lock, flags);
    if (throttled){
        pr_err("usb_serial_highspeed_rx_tasklet : throttled\n");
        return;
        }

next_buffer:
    spin_lock_irqsave(&acm->read_lock, flags);
    if (list_empty(&acm->filled_read_bufs)) {
        spin_unlock_irqrestore(&acm->read_lock, flags);
        goto urbs;
    }
    buf = list_entry(acm->filled_read_bufs.next,
             struct acm_rb, list);
    list_del(&buf->list);
    spin_unlock_irqrestore(&acm->read_lock, flags);

    dbg("usb_serial_highspeed_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);

//    if(buf->size &&(ncount || (buf->base[0] == 1))){
    if(buf->size ){
        test[ncount] = buf->base[0];
        ncount++;
        zcount = 0;
        if(ncount == 64) ncount = 0;

        tty_buffer_request_room(tty, buf->size);
        spin_lock_irqsave(&acm->throttle_lock, flags);
        throttled = acm->throttle;
        spin_unlock_irqrestore(&acm->throttle_lock, flags);
        if (!throttled){
            if(buf->size > tty_insert_flip_string(tty, buf->base, buf->size))
                pr_err("\n===== tty_insert_flip_string ====\n");;
            recvcount++;
            }
        tty_flip_buffer_push(tty);

        if (throttled) {
            dbg("Throttling noticed");
            spin_lock_irqsave(&acm->read_lock, flags);
            list_add(&buf->list, &acm->filled_read_bufs);
            spin_unlock_irqrestore(&acm->read_lock, flags);
            pr_err("usb_serial_highspeed_rx_tasklet : throttled 2!!\n");
            return;
        }
    }
    else{
        zcount++;
        if(ncount && ncount != 32){
#ifdef NEVER
            int i;
            printk("\nncount : %d\n", ncount);
            for( i = 0; i <ncount; i++)
                printk("ncount - test: %02x\n", test[i]);
#endif /* NEVER */
            ncount = 0;
            }
        if(zcount >1)
            pr_err("zcount : %d\n",zcount);
        ncount = 0;
    }

    spin_lock_irqsave(&acm->read_lock, flags);
    list_add(&buf->list, &acm->spare_read_bufs);
    spin_unlock_irqrestore(&acm->read_lock, flags);
    goto next_buffer;

urbs:
    while (!list_empty(&acm->spare_read_bufs)) {
        spin_lock_irqsave(&acm->read_lock, flags);
        if (list_empty(&acm->spare_read_urbs)) {
            spin_unlock_irqrestore(&acm->read_lock, flags);
            return;
        }
        if(acm->skip){
            acm->skip = 0;
            spin_unlock_irqrestore(&acm->read_lock, flags);
            pr_err("usb_serial_highspeed_rx_tasklet : skip \n");
            return;
            }
        rcv = list_entry(acm->spare_read_urbs.next,
                 struct acm_ru, list);
        list_del(&rcv->list);
        //spin_unlock_irqrestore(&acm->read_lock, flags);

        buf = list_entry(acm->spare_read_bufs.next,
                 struct acm_rb, list);
        list_del(&buf->list);
        testcount ++;
        spin_unlock_irqrestore(&acm->read_lock, flags);

        rcv->buffer = buf;

        usb_fill_bulk_urb(rcv->urb, acm->dev,
                  acm->rx_endpoint,
                  buf->base,
                  acm->readsize,
                  usb_serial_highspeed_read_bulk_callback, rcv);
        rcv->urb->transfer_dma = buf->dma;
        rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

        dbg("usb_serial_highspeed_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);

        /* This shouldn't kill the driver as unsuccessful URBs are returned to the
           free-urbs-pool and resubmited ASAP */
        if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
            spin_lock_irqsave(&acm->read_lock, flags);
            list_add(&buf->list, &acm->spare_read_bufs);
            list_add(&rcv->list, &acm->spare_read_urbs);
            testcount --;
            spin_unlock_irqrestore(&acm->read_lock, flags);
            pr_err("usb_serial_highspeed_rx_tasklet : usb_submit_urb failure \n");
            return;
        }
    }
}


/* data interface returns incoming bytes, or we got unthrottled */
static void usb_serial_highspeed_read_bulk_callback(struct urb *urb)
{
    struct acm_rb *buf;
    struct acm_ru *rcv = urb->context;
    struct acm *acm = rcv->instance;
    int status = urb->status;

    dbg("usb_serial_highspeed_read_bulk_callback with status %d", status);

    if (!PORT_READY(acm))
        return;

    if (status)
        dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);

#ifdef CONFIG_ANDROID_POWER
//    userial_auto_suspend();
    userial_auto_lock_suspend();
#endif

    buf = rcv->buffer;
    buf->size = urb->actual_length;

//    if (likely(status == 0)||unlikely(buf->size == 0)) {
    if (likely(status == 0)) {
        spin_lock(&acm->read_lock);
        list_add_tail(&rcv->list, &acm->spare_read_urbs);
        list_add_tail(&buf->list, &acm->filled_read_bufs);
        testcount --;
        spin_unlock(&acm->read_lock);
        tasklet_schedule(&acm->urb_task);
    } else {
        /* we drop the buffer due to an error */
        spin_lock(&acm->read_lock);
        list_add_tail(&rcv->list, &acm->spare_read_urbs);
        list_add(&buf->list, &acm->spare_read_bufs);
        testcount --;
        spin_unlock(&acm->read_lock);
        /* nevertheless the tasklet must be kicked unconditionally
        so the queue cannot dry up */
        acm->skip = 1;
    }
}

int usb_serial_highspeed_usb_count(void)
{
    pr_err("%s - testcount %d recvcount%d \n", __FUNCTION__, testcount, recvcount);
    return testcount;
}
EXPORT_SYMBOL_GPL(usb_serial_highspeed_usb_count);

void usb_serial_highspeed_throttle (struct usb_serial_port *port)
{
    unsigned long flags;
    struct acm * acm =usb_get_serial_port_data(port);

    //dbg("%s - port %d", __FUNCTION__, port->number);
    pr_err("%s - port %d", __FUNCTION__, port->number);

    /* Set the throttle request flag. It will be picked up
     * by usb_serial_highspeed_read_bulk_callback(). */
    spin_lock_irqsave(&port->lock, flags);
    acm->throttle = 1;
    spin_unlock_irqrestore(&port->lock, flags);
}

void usb_serial_highspeed_unthrottle (struct usb_serial_port *port)
{
    int was_throttled;
    unsigned long flags;
    struct acm * acm =usb_get_serial_port_data(port);

    //dbg("%s - port %d", __FUNCTION__, port->number);
    pr_err("%s - port %d\n", __FUNCTION__, port->number);

    /* Clear the throttle flags */
    spin_lock_irqsave(&port->lock, flags);
    was_throttled = acm->throttle;
    acm->throttle = 0;
    spin_unlock_irqrestore(&port->lock, flags);

    if (was_throttled) {
        /* Resume reading from device */
        acm->skip = 0;
        tasklet_schedule(&acm->urb_task);
    }
}

void usb_serial_highspeed_shutdown (struct usb_serial *serial)
{
    int i;

    dbg("%s\n", __FUNCTION__);

    /* stop reads and writes on all ports */
    for (i=0; i < serial->num_ports; ++i) {
        usb_serial_highspeed_cleanup(serial->port[i]);
    }
}


int usb_serial_highspeed_probe(struct usb_serial_port *port)
{
    struct usb_interface *interface = port->serial->interface;
    struct usb_device *dev = interface_to_usbdev (interface);
    int i;
    int num_bulk_in = 1;
    int num_bulk_out = 1;

    int num_rx_buf = ACM_NR;
    struct acm* acm =     usb_get_serial_port_data (port );


    pr_err("%s: port data -- %d\n", __FUNCTION__, (int)acm);

    if(acm){
        pr_err("\n error !usb_serial_highspeed_probe call exception!!\n ");
        return 0;
        }

    lock_kernel(); /* guard against unloading a serial driver module */
    acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
    if (!port){
        unlock_kernel();
        pr_err("\n error ! no memory !!\n ");
        goto probe_error;
        }

    /* set up the endpoint information */
    for (i = 0; i < num_bulk_in; ++i) {
        int readsize;

        readsize = port->bulk_in_size;
        acm->data = interface;
        acm->dev = dev;
        acm->readsize = readsize;
        acm->rx_buflimit = num_rx_buf;
        acm->urb_task.func = usb_serial_highspeed_rx_tasklet;
        acm->urb_task.data = (unsigned long) acm;
        spin_lock_init(&acm->throttle_lock);
        spin_lock_init(&acm->read_lock);
        mutex_init(&acm->mutex);

        acm->rx_endpoint = usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress);

        for (i = 0; i < num_rx_buf; i++) {
            struct acm_ru *rcv = &(acm->ru[i]);

            if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
                dev_dbg(&interface->dev, "out of memory (read urbs usb_alloc_urb)\n");
                unlock_kernel();
                goto alloc_fail7;
            }

            rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
            rcv->instance = acm;
        }
        for (i = 0; i < num_rx_buf; i++) {
            struct acm_rb *buf = &(acm->rb[i]);

            if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
                dev_dbg(&interface->dev, "out of memory (read bufs usb_buffer_alloc)\n");
                unlock_kernel();
                goto alloc_fail7;
            }
        }
    }

    for (i = 0; i < num_bulk_out; ++i) {

        acm->writesize = le16_to_cpu(port->bulk_out_size);


        INIT_WORK(&acm->work, acm_softint);
        spin_lock_init(&acm->write_lock);
        acm->write_ready = 1;

    for (i = 0; i < ACM_NW; i++) {
        struct acm_ru *wu = &(acm->wu[i]);

        if (!(wu->urb = usb_alloc_urb(0, GFP_KERNEL))) {
            dev_dbg(&interface->dev, "out of memory (read urbs usb_alloc_urb)\n");
            unlock_kernel();
            goto alloc_fail7;
        }
        usb_fill_bulk_urb(wu->urb, dev, usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
              NULL, acm->writesize, acm_write_bulk, acm);
        wu->urb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
        wu->instance = acm;
    }
    for (i = 0; i < ACM_NW; i++) {
        struct acm_rb *rbuf = &(acm->wb[i]);

        if (!(rbuf->base = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL, &rbuf->dma))) {
            dev_dbg(&interface->dev, "out of memory (read bufs usb_buffer_alloc)\n");
            unlock_kernel();
            goto alloc_fail8;
        }
    }

    }
    unlock_kernel();

    /* success */
    usb_set_serial_port_data (port, acm);
    return 0;

alloc_fail8:
    for (i = 0; i < ACM_NW; i++) {
        struct acm_ru *wu = &(acm->wu[i]);

        usb_free_urb(wu->urb);
    }
    acm_write_buffers_free(acm);
alloc_fail7:
    for (i = 0; i < num_rx_buf; i++)
        usb_buffer_free(acm->dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
    for (i = 0; i < num_rx_buf; i++)
        usb_free_urb(acm->ru[i].urb);

probe_error:

    return -EIO;
}


int usb_serial_highspeed_disconnect(struct usb_serial_port *port)
{
    int i;

    int num_rx_buf = ACM_NR;
    struct acm* acm = usb_get_serial_port_data(port);

    pr_err("%s\n", __FUNCTION__);

    lock_kernel(); /* guard against unloading a serial driver module */
    for (i = 0; i < ACM_NW; i++) {
        struct acm_ru *wu = &(acm->wu[i]);

        usb_free_urb(wu->urb);
    }

    for (i = 0; i < num_rx_buf; i++)
        usb_buffer_free(acm->dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
    for (i = 0; i < num_rx_buf; i++)
        usb_free_urb(acm->ru[i].urb);

    acm_write_buffers_free(acm);

    kfree(acm);

    /* success */
    usb_set_serial_port_data (port, NULL);
    unlock_kernel();
    return 0;
}


static struct usb_driver generic_high_driver = {
    .name =        "usbserial_high",
    .probe =    generic_probe,
    .suspend =  generic_suspend,
    .resume  =  generic_resume,
    .disconnect =    usb_serial_disconnect,
    .id_table =    hs_serial_ids,
    .no_dynamic_id =    1,
};

/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_driver usb_serial_highspeed_device = {
    .driver = {
        .owner =    THIS_MODULE,
        .name =        "high-speed",
    },
    .id_table =        hs_device_ids,
    .usb_driver =         &generic_high_driver,
    .num_interrupt_in =    NUM_DONT_CARE,
    .num_bulk_in =        NUM_DONT_CARE,
    .num_bulk_out =        NUM_DONT_CARE,
    .num_ports =        1,
    .port_probe =    usb_serial_highspeed_probe,
    .port_remove = usb_serial_highspeed_disconnect,    
    .open =    usb_serial_highspeed_open,
    .write =    usb_serial_highspeed_write,
    .close =    usb_serial_highspeed_close,
    .write_room =    usb_serial_highspeed_write_room,
    .chars_in_buffer =    usb_serial_highspeed_chars_in_buffer,
    .shutdown =        usb_serial_highspeed_shutdown,
    .throttle =        usb_serial_highspeed_throttle,
    .unthrottle =        usb_serial_highspeed_unthrottle,
    .suspend =        usb_serial_highspeed_suspend,
    .resume =        usb_serial_highspeed_resume,
};


static int __init usb_serial_highspeed_init(void)
{
    int retval = 0;

    hs_device_ids[0].idVendor = vendor;
    hs_device_ids[0].idProduct = product;
    hs_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;

    /* register our generic driver with ourselves */
    retval = usb_serial_register (&usb_serial_highspeed_device);
    if (retval)
        goto exit;
    retval = usb_register(&generic_high_driver);
    if (retval)
        usb_serial_deregister(&usb_serial_highspeed_device);
exit:
    info(DRIVER_DESC " " DRIVER_VERSION);
    return retval;
}

static void __exit usb_serial_highspeed_exit(void)
{
    usb_deregister(&generic_high_driver);
    usb_serial_deregister (&usb_serial_highspeed_device);
}

module_init(usb_serial_highspeed_init);
module_exit(usb_serial_highspeed_exit);

/* Module information */
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");

基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip 个人大四的毕业设计、课程设计、作业、经导师指导并认可通过的高分设计项目,评审平均分达96.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 [资源说明] 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设或者课设、作业,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96.5分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),供学习参考。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值