temp

/*
 * USB webcameton 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-webcameton.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_WEBCAM_VENDOR_ID        0x046d
#define USB_WEBCAM_PRODUCT_ID    0x09a4

#define VEDIO_CONTROL_NUM        0
#define VEDIO_STREAMING_NUM    1
#define AUDIO_STREAMING_NUM    3

#define VEDIO_WMAXPACKETSIZE_800BYTES    5
#define AUDIO_WMAXPACKETSIZE_36BYTES    1
#define HID_WMAXPACKETSIZE_16BYTES    0


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


/*disconnect id*/
int disconn_id;
/* Get a minor range for your devices from the usb maintainer */
#define USB_WEBCAM_HID_MINOR_BASE    192
#define USB_WEBCAM_VEDIO_MINOR_BASW    200
#define USB_WEBCAM_AUDIO_MINOR_BASW    210

/* Structure to hold all of our device specific stuff */
struct usb_webcam {
    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 */
    unsigned char *        int_buffer;
    size_t            isoc_in_size;        /* the size of the receive buffer */
    size_t            int_size;
    __u8            isoc_in_endpointAddr;    /* the address of the isoc in endpoint */
    __u8            isoc_out_endpointAddr;    /* the address of the isoc out endpoint */
    __u8            int_endpointAddr;
    struct kref        kref;
};
#define to_webcam_dev(d) container_of(d, struct usb_webcam, kref)

static struct usb_driver webcam_driver;

static void webcam_delete(struct kref *kref)
{   
    struct usb_webcam *dev = to_webcam_dev(kref);
    usb_put_dev(dev->udev);
    kfree (dev->isoc_in_buffer);
    kfree(dev->int_buffer);
    kfree (dev);
}

static int webcam_open(struct inode *inode, struct file *file)
{
    struct usb_webcam *dev;
    struct usb_interface *interface;
    int subminor;
    int retval = 0;

    subminor = iminor(inode);

    interface = usb_find_interface(&webcam_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;

exit:
    return retval;
}

static int webcam_release(struct inode *inode, struct file *file)
{
    struct usb_webcam *dev;

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

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

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

    dev = (struct usb_webcam *)file->private_data;
   
    /* do a blocking isoc read to get data from the device */
    retval = usb_bulk_msg(dev->udev,
                  usb_rcvisocpipe(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 webcam_write_isoc_callback(struct urb *urb)
{
    /* sync/async unlink faults aren't errors */
    if (urb->status &&
        !(urb->status == -ENOENT ||
          urb->status == -ECONNRESET ||
          urb->status == -ESHUTDOWN)) {
        dbg("%s - nonzero write isoc 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 webcam_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos)
{
    struct usb_webcam *dev;
    int retval = 0;
    struct urb *urb = NULL;
    char *buf = NULL;

    dev = (struct usb_webcam *)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_sndisocpipe(dev->udev, dev->isoc_out_endpointAddr),
              buf, count, webcam_write_isoc_callback, dev);
    urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    /* send the data out the isoc 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 webcam_fops = {
    .owner =    THIS_MODULE,
    .read =        webcam_read,
    .write =    webcam_write,
    .open =        webcam_open,
    .release =    webcam_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 webcam_hid_class = {
    .name = "/Logitech/camhid%d",
    .fops = &webcam_fops,
    //.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
    .minor_base = USB_WEBCAM_HID_MINOR_BASE,
};
static struct usb_class_driver webcam_vedio_class = {
    .name = "/Logitech/camvedio%d",
    .fops = &webcam_fops,
    //.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
    .minor_base = USB_WEBCAM_VEDIO_MINOR_BASW,
};
static struct usb_class_driver webcam_audio_class={
    .name="/Logitech/camaudio%d",
    .fops=&webcam_fops,
    .minor_base =USB_WEBCAM_AUDIO_MINOR_BASW,
};
static int webcam_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
    struct usb_webcam *dev = NULL;
    struct usb_host_interface *iface_desc=NULL;
    struct usb_endpoint_descriptor *endpoint=NULL;
    struct usb_class_driver *cur_usb_class=NULL;
    __u8 select_setting;
    size_t buffer_size;
    int flag=0;
    int i;
    int retval = -ENOMEM;
    iface_desc=interface->cur_altsetting ;
     /* allocate memory for our device state and initialize it */
    dev = kmalloc(sizeof(struct usb_webcam), GFP_KERNEL);
    if (dev == NULL) {
        err("Out of memory");
        goto error;
    };
    memset(dev, 0x00, sizeof (*dev));
    kref_init(&dev->kref);

    dev->udev = usb_get_dev(interface_to_usbdev(interface));
    dev->interface = interface;printk("%d/n",iface_desc->desc.bInterfaceNumber);
    switch(iface_desc->desc.bInterfaceNumber)
    {
        case VEDIO_CONTROL_NUM:printk("interupt/n");
                select_setting=HID_WMAXPACKETSIZE_16BYTES;
                cur_usb_class=&webcam_hid_class;
                flag=1;
                                disconn_id++;
                break;
        case VEDIO_STREAMING_NUM:printk("vedio/n");
                select_setting=VEDIO_WMAXPACKETSIZE_800BYTES;
                cur_usb_class=&webcam_vedio_class;
                disconn_id++;
                break;
        case AUDIO_STREAMING_NUM:printk("audio/n");
                select_setting=AUDIO_WMAXPACKETSIZE_36BYTES;
                cur_usb_class=&webcam_audio_class;
                disconn_id++;               
                break;
        default:
                goto error;
    }
    /* set up the endpoint information */
    for(i=0;i<interface->num_altsetting;i++){
        if(interface->altsetting[i].desc.bAlternateSetting==select_setting){
            interface->cur_altsetting=interface->altsetting+i;
            iface_desc=interface->cur_altsetting;
            endpoint=&iface_desc->endpoint->desc;
            break;
        }
    }
    if (!dev->isoc_in_endpointAddr &&usb_endpoint_xfer_isoc(endpoint)) {
        /* we found a isoc in endpoint */
        buffer_size = endpoint->wMaxPacketSize;
        dev->isoc_in_size = buffer_size;
        dev->isoc_in_endpointAddr = endpoint->bEndpointAddress;
        dev->interface = interface;
        dev->isoc_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
        if (!dev->isoc_in_buffer) {
            err("Could not allocate isoc_in_buffer");
            goto error;
        }
     }
    if(!dev->int_endpointAddr&&usb_endpoint_xfer_int(endpoint)){
        buffer_size = endpoint->wMaxPacketSize;
        dev->int_size = buffer_size;
        dev->int_endpointAddr = endpoint->bEndpointAddress;
        dev->interface = interface;
        dev->int_buffer = kmalloc(buffer_size, GFP_KERNEL);
        if (!dev->int_buffer) {
            err("Could not allocate isoc_in_buffer");
            goto error;
        }       
    }
/*
    if (!dev->isoc_out_endpointAddr &&usb_endpoint_is_isoc_out(endpoint)){
        printk("find 0ut/n");
        dev->isoc_out_endpointAddr = endpoint->bEndpointAddress;
    }
    if (!(dev->isoc_in_endpointAddr || dev->isoc_out_endpointAddr)) {
        err("Could not find both isoc-in and isoc-out endpoints");
        goto error;
    }
*/
    /* save our data pointer in this interface device */
    usb_set_intfdata(interface, dev);

    /* we can register the device now, as it is ready */
    retval = usb_register_dev(interface, cur_usb_class);
    if (retval) {
        /* something prevented us from registering this driver */
        err("Not able to get a minor for this device.");
        usb_set_intfdata(interface, NULL);
        goto error;
    }
    if(flag==1)
    {
            char data=0x0;
        flag=usb_control_msg(dev->udev,usb_sndctrlpipe(dev->udev,0),0x05,USB_DIR_OUT | USB_TYPE_VENDOR |
                 USB_RECIP_DEVICE,0x3200,0,&data,1,500);   
        if(flag<0)
        {printk("powe on failed%d/n",flag);}
        else
        printk("successfully");
    }
    /* let the user know what node this device is now attached to */
    info("USB webcame device now attached to USBwebcam-%d", interface->minor);
    return 0;

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

static void webcam_disconnect(struct usb_interface *interface)
{
    struct usb_webcam *dev;
    int minor = interface->minor;

    /* prevent webcam_open() from racing webcam_disconnect() */
    lock_kernel();

    dev = usb_get_intfdata(interface);
    usb_set_intfdata(interface, NULL);

    /* give back our minor */
        if(disconn_id%3==0)
    {   
        usb_deregister_dev(interface, &webcam_hid_class);
        disconn_id--;
    }
    else if(disconn_id%3==2)
    {
        usb_deregister_dev(interface, &webcam_vedio_class);
        disconn_id--;
    }
    else
    {
        usb_deregister_dev(interface, &webcam_audio_class);
        disconn_id--;
    }

   
    /*usb_deregister_dev(interface, &webcam_hid_class);
    usb_deregister_dev(interface, &webcam_audio_class);*/
    unlock_kernel();

    /* decrement our usage count */
    kref_put(&dev->kref, webcam_delete);

    info("USB webcame #%d now disconnected", minor);
}

static struct usb_driver webcam_driver = {
    //.owner = THIS_MODULE,
    .name = "Logitech",
    .id_table = webcam_table,
    .probe = webcam_probe,
    .disconnect = webcam_disconnect,
};

static int __init usb_webcam_init(void)
{
    int result;

    /* register this driver with the USB subsystem */
    result = usb_register(&webcam_driver);
    if (result)
        err("usb_register failed. Error number %d", result);

    return result;
}

static void __exit usb_webcam_exit(void)
{
    /* deregister this driver with the USB subsystem */
    usb_deregister(&webcam_driver);
}

module_init (usb_webcam_init);
module_exit (usb_webcam_exit);

MODULE_LICENSE("GPL");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值