随手

/*
 * USB Skeleton driver - 2.0
 *
 * Copyright (C) 2001-2004 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 as
 *    published by the Free Software Foundation, version 2.
 *
 * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
 * but has been rewritten to be easy to read and use, as no locks are now
 * needed anymore.
 *
 */


#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <asm/uaccess.h>


/* Define these values to match your devices */
#define USB_SKEL_VENDOR_ID    0x046d
#define USB_SKEL_PRODUCT_ID    0x09a4

/* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {
    { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
    { }                    /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, skel_table);

#define USB_HID_MINOR_BASE    90                /*Hid设备的次设备号基准*/
#define USB_VIDEO_MINOR_BASE    100            /*Video设备的次设备号基准*/
#define USB_AUDIO_MINOR_BASE    110            /*Audio设备的次设备号基准*/

#define VIDEO_800BYTES 4                       /*Video接口选用4号接口配置*/
#define AUDIO_36BYTES 1                        /*Audio接口选用1号接口配置*/
#define HID_16BYTES 0                           /*Hid接口使用唯一的0号接口配置*/

#define MAX_DEV_NUM 20

/* Structure to hold all of our device specific stuff */
struct usb_skel {
    struct usb_device *    udev;            /* the usb device for this device */
    struct usb_interface *    interface;        /* the interface for this device */
    unsigned char *        isoc_in_buffer;        /* the buffer to receive data */
    size_t            isoc_in_size;        /* the size of the receive buffer */
    __u8            isoc_in_endpointAddr;    /* the address of the bulk in endpoint */
    __u8            isoc_out_endpointAddr;    /* the address of the bulk out endpoint */
    struct kref        kref;
};

#define to_skel_dev(d) container_of(d, struct usb_skel, kref)

static struct usb_driver skel_driver;

static void skel_delete(struct kref *kref)
{   
    struct usb_skel *dev = to_skel_dev(kref);
    usb_put_dev(dev->udev);
    kfree (dev->isoc_in_buffer);
    kfree (dev);
}

static int skel_open(struct inode *inode, struct file *file)
{
    struct usb_skel *dev;
    struct usb_interface *interface;
    int subminor;
    int retval = 0;
   
    subminor = iminor(inode);

    interface = usb_find_interface(&skel_driver, subminor);
    if (!interface) {
        err ("%s - error, can't find device for minor %d",
             __FUNCTION__, subminor);
        retval = -ENODEV;
        goto exit;
    }

    dev = usb_get_intfdata(interface);
    if (!dev) {
        retval = -ENODEV;
        goto exit;
    }
   
    /* increment our usage count for the device */
    kref_get(&dev->kref);

    /* save our object in the file's private structure */
    file->private_data = dev;
   
    return 0;

exit:
    return retval;
}

static int skel_release(struct inode *inode, struct file *file)
{
    struct usb_skel *dev;

    dev = (struct usb_skel *)file->private_data;
    if (dev == NULL)
        return -ENODEV;

    /* decrement the count on our device */
    kref_put(&dev->kref, skel_delete);
    return 0;
}

static ssize_t skel_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
    struct usb_skel *dev;
    int retval = 0;

    dev = (struct usb_skel *)file->private_data;
   
    /* do a blocking bulk read to get data from the device */
    retval = usb_bulk_msg(dev->udev,
                  usb_rcvbulkpipe(dev->udev, dev->isoc_in_endpointAddr),
                  dev->isoc_in_buffer,
                  min(dev->isoc_in_size, count),
                  &count, HZ*10);

    /* if the read was successful, copy the data to userspace */
    if (!retval) {
        if (copy_to_user(buffer, dev->isoc_in_buffer, count))
            retval = -EFAULT;
        else
            retval = count;
    }

    return retval;
}

static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
    /* sync/async unlink faults aren't errors */
    if (urb->status &&
        !(urb->status == -ENOENT ||
          urb->status == -ECONNRESET ||
          urb->status == -ESHUTDOWN)) {
        dbg("%s - nonzero write bulk status received: %d",
            __FUNCTION__, urb->status);
    }

    /* free up our allocated buffer */
    usb_buffer_free(urb->dev, urb->transfer_buffer_length,
            urb->transfer_buffer, urb->transfer_dma);
}

static ssize_t skel_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos)
{
    struct usb_skel *dev;
    int retval = 0;
    struct urb *urb = NULL;
    char *buf = NULL;

    dev = (struct usb_skel *)file->private_data;

    /* verify that we actually have some data to write */
    if (count == 0)
        goto exit;

    /* create a urb, and a buffer for it, and copy the data to the urb */
    urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!urb) {
        retval = -ENOMEM;
        goto error;
    }

    buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
    if (!buf) {
        retval = -ENOMEM;
        goto error;
    }
    if (copy_from_user(buf, user_buffer, count)) {
        retval = -EFAULT;
        goto error;
    }

    /* initialize the urb properly */
    usb_fill_bulk_urb(urb, dev->udev,
              usb_sndbulkpipe(dev->udev, dev->isoc_out_endpointAddr),
              buf, count, (usb_complete_t)skel_write_bulk_callback, dev);
    urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    /* send the data out the bulk port */
    retval = usb_submit_urb(urb, GFP_KERNEL);
    if (retval) {
        err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
        goto error;
    }

    /* release our reference to this urb, the USB core will eventually free it entirely */
    usb_free_urb(urb);

exit:
    return count;

error:
    usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
    usb_free_urb(urb);
    kfree(buf);
    return retval;
}

static struct file_operations skel_fops = {
    .owner =    THIS_MODULE,
    .read =        skel_read,
    .write =    skel_write,
    .open =        skel_open,
    .release =    skel_release,
};

/*
 * usb class driver info in order to get a minor number from the usb core,
 * and to have the device registered with devfs and the driver core
 */
static struct usb_class_driver video_class = {
    .name = "Cam_video%d",
    .fops = &skel_fops,
    .minor_base = USB_VIDEO_MINOR_BASE,
};

static struct usb_class_driver audio_class = {
    .name = "Cam_audio%d",
    .fops = &skel_fops,
    .minor_base = USB_AUDIO_MINOR_BASE,
};

static struct usb_class_driver hid_class = {
    .name = "Cam_HID%d",
    .fops = &skel_fops,
    .minor_base = USB_HID_MINOR_BASE,
};

/*探测函数*/
static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
    struct usb_skel *dev = NULL;
    struct usb_host_interface *iface_desc;
    struct usb_endpoint_descriptor *endpoint=NULL;
    struct usb_class_driver *ucd=NULL;
    size_t buffer_size;
    int i;
    int retval = -ENOMEM;
    int alterSetting;       /*接口号*/
    int interfaceNumber;    /*接口选择的配置号*/
    int dev_no;             /*设备号*/
   
    /*为usb_skel结构体申请空间*/
    dev = kmalloc(sizeof(struct usb_skel), GFP_KERNEL);
    if (dev == NULL)
    {
        err("Out of memory");
        goto error;
    }
    /*用0x00初始化刚才申请的空间*/
    memset(dev, 0x00, sizeof (*dev));
    /*设置kref->refcount的引用计数为1*/
    kref_init(&dev->kref);

    alterSetting=-1;
    /*通过端口得到usb_device,并使设备的应用加1*/
    dev->udev = usb_get_dev(interface_to_usbdev(interface));
    dev->interface = interface;
    /*得到当前的接口配置*/
    iface_desc=interface->cur_altsetting;
    printk("----InterfaceNumber is %d---/n",iface_desc->desc.bInterfaceNumber);
   
    /*获得当前的接口号*/
    interfaceNumber=iface_desc->desc.bInterfaceNumber;
    /*video*/
    if(interfaceNumber==1)
    {   
        /*video选择的是1号接口的,VIDEO_800BYTES号接口配置*/
        alterSetting=VIDEO_800BYTES;       
        ucd=&video_class;   
    }
    /*audio*/
    else if(interfaceNumber==3)
    {       
        /*audio选择的是3号接口的,AUDIO_36BYTES号接口配置*/
        alterSetting=AUDIO_36BYTES;
        ucd=&audio_class;
    }
    /*hid*/
    else if(interfaceNumber==0)
    {               
        /*audio选择的是0号接口的,使用HID_16BYTES号接口配置*/
        alterSetting=HID_16BYTES;
        ucd=&hid_class;
    }   
    /*其他接口*/
    else
    {
        return 0;
    }

    /*设置相应接口的相应接口配置*/
    for(i=0;i<interface->num_altsetting;i++)
    {
        if(interface->altsetting[i].desc.bAlternateSetting==alterSetting)
        {
            interface->cur_altsetting=interface->altsetting+i;
            iface_desc = interface->cur_altsetting;
            endpoint = &iface_desc->endpoint->desc;
            break;
        }
    }
    /*如果是video和audio接口,得到相应的iso等时端点值*/
    if(interfaceNumber==1||interfaceNumber==3)
    {
        if ((usb_endpoint_is_isoc_in(endpoint)))
        {
            /*找到一个等时类型的端点*/
            buffer_size = endpoint->wMaxPacketSize;
            dev->isoc_in_size = buffer_size;
            dev->isoc_in_endpointAddr = endpoint->bEndpointAddress;
            dev->isoc_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
            if (!dev->isoc_in_buffer)
            {
                err("Could not allocate iso_in_buffer");
                goto error;
            }
        }
    }
    /*如果是hid接口,得到相应的intrupt中断端点值*/
    if(interfaceNumber==0)
    {
        if((!dev->isoc_in_endpointAddr)&&(usb_endpoint_is_int_in(endpoint)))
        {
            /*找到一个中断类型的端点*/
            buffer_size = endpoint->wMaxPacketSize;
            dev->isoc_in_size = buffer_size;
            dev->isoc_in_endpointAddr = endpoint->bEndpointAddress;
            dev->isoc_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
            if (!dev->isoc_in_buffer)
            {
                err("Could not allocate int_in_buffer");
                goto error;
            }
        }
    }
    /*这两种类型的都没有找到 */
    if (!(dev->isoc_in_endpointAddr))
    {
        err("Could not find both iso_in and int_out endpoints");
        goto error;
    }

    /*把dev保存在interface接口中*/
    usb_set_intfdata(interface, dev);

    /*注册usb接口*/
    retval = usb_register_dev(interface, ucd);
    if (retval)
    {
        /*打印注册失败消息,并清除保存在interface中的数据*/
        err("Not able to get a minor for this device.");
        usb_set_intfdata(interface, NULL);
        goto error;
    }
   
    char data=0x00;
    /*------------------------power test---------------------*/
    retval=usb_control_msg(dev->udev,
                           usb_sndctrlpipe(dev->udev,0),
                            0x05,   //request 设置设备地址
                            USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, //requesttype节点类型是输出,自定义方式,输出到设备
                            0x3200,     //value
                            0,          //index 通过0号接口
                            &data,      //data
                            sizeof(char),  //size
                            1000);
    printk("**************%d*************/n",retval);
   
    return 0;
    /*-------------------------------------------------------*/
   
   
    /*输出usb设备成功连接信息*/
    info("USB Skeleton device now attached to USBSkel-%d", interface->minor);
    return 0;

error:
    if (dev)
        kref_put(&dev->kref, skel_delete);
    return retval;
}

static void skel_disconnect(struct usb_interface *interface)
{
    struct usb_skel *dev;
    struct usb_host_interface *iface_desc;
    int minor = interface->minor;
    struct usb_class_driver *ucd=NULL;
   
    /* 从interface中得到usb_skel*/
    dev=usb_get_intfdata(interface);
    /*得到当前设置*/
    iface_desc=interface->cur_altsetting;
    /*加锁*/
    lock_kernel();
    /*video接口*/
    if(iface_desc->desc.bInterfaceNumber==1)
    {
        printk("interface is %d/n",iface_desc->desc.bInterfaceClass);
        ucd=&video_class;
    }
    /*hid接口*/
    else if(iface_desc->desc.bInterfaceNumber==0)
    {
        printk("interface is %d/n",iface_desc->desc.bInterfaceClass);
        ucd=&hid_class;
    }
    /*audio接口*/
    else if(iface_desc->desc.bInterfaceNumber==3)
    {
        printk("interface is %d/n",iface_desc->desc.bInterfaceClass);
        ucd=&audio_class;
    }
    /*其他接口*/
    else
    {
        return ;
    }
   
    /*清空interface中保存的数据 */
    usb_set_intfdata(interface, NULL);
    /*取消接口注册*/
    usb_deregister_dev(interface,ucd);
    /*释放资源*/
    kref_put(&dev->kref, skel_delete);
    /*解锁*/
    unlock_kernel();
   
    info("USB Skeleton #%d now disconnected", minor);
}


static struct usb_driver skel_driver = {
    .name = "skel%d",
    .id_table = skel_table,
    .probe = skel_probe,
    .disconnect = skel_disconnect,
};

/*usb驱动注册函数*/
static int __init usb_skel_init(void)
{
    int result;

    /*注册usb设备到内核*/
    result = usb_register(&skel_driver);
    if (result)
        err("usb_register failed. Error number %d", result);

    return result;
}

/*usb驱动撤销函数*/
static void __exit usb_skel_exit(void)
{
    /*从内核中移出usb设备*/
    usb_deregister(&skel_driver);
}

module_init (usb_skel_init);
module_exit (usb_skel_exit);

MODULE_LICENSE("GPL");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值