1/* 2 * Fushicai USBTV007 Audio-Video Grabber Driver 3 * 4 * Product web site: 5 * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html 6 * 7 * Following LWN articles were very useful in construction of this driver: 8 * Video4Linux2 API series: http://lwn.net/Articles/203924/ 9 * videobuf2 API explanation: http://lwn.net/Articles/447435/ 10 * Thanks go to Jonathan Corbet for providing this quality documentation. 11 * He is awesome. 12 * 13 * Copyright (c) 2013 Lubomir Rintel 14 * All rights reserved. 15 * No physical hardware was harmed running Windows during the 16 * reverse-engineering activity 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions, and the following disclaimer, 23 * without modification. 24 * 2. The name of the author may not be used to endorse or promote products 25 * derived from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL"). 29 */ 30 31#include "usbtv.h" 32 33int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) 34{ 35 int ret; 36 int pipe = usb_rcvctrlpipe(usbtv->udev, 0); 37 int i; 38 39 for (i = 0; i < size; i++) { 40 u16 index = regs[i][0]; 41 u16 value = regs[i][1]; 42 43 ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG, 44 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 45 value, index, NULL, 0, 0); 46 if (ret < 0) 47 return ret; 48 } 49 50 return 0; 51} 52 53static int usbtv_probe(struct usb_interface *intf, 54 const struct usb_device_id *id) 55{ 56 int ret; 57 int size; 58 struct device *dev = &intf->dev; 59 struct usbtv *usbtv; 60 61 /* Checks that the device is what we think it is. */ 62 if (intf->num_altsetting != 2) 63 return -ENODEV; 64 if (intf->altsetting[1].desc.bNumEndpoints != 4) 65 return -ENODEV; 66 67 /* Packet size is split into 11 bits of base size and count of 68 * extra multiplies of it.*/ 69 size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc); 70 size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1); 71 72 /* Device structure */ 73 usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL); 74 if (usbtv == NULL) 75 return -ENOMEM; 76 usbtv->dev = dev; 77 usbtv->udev = usb_get_dev(interface_to_usbdev(intf)); 78 79 usbtv->iso_size = size; 80 81 usb_set_intfdata(intf, usbtv); 82 83 ret = usbtv_video_init(usbtv); 84 if (ret < 0) 85 goto usbtv_video_fail; 86 87 ret = usbtv_audio_init(usbtv); 88 if (ret < 0) 89 goto usbtv_audio_fail; 90 91 /* for simplicity we exploit the v4l2_device reference counting */ 92 v4l2_device_get(&usbtv->v4l2_dev); 93 94 dev_info(dev, "Fushicai USBTV007 Audio-Video Grabber\n"); 95 return 0; 96 97usbtv_audio_fail: 98 usbtv_video_free(usbtv); 99 100usbtv_video_fail: 101 usb_set_intfdata(intf, NULL); 102 usb_put_dev(usbtv->udev); 103 kfree(usbtv); 104 105 return ret; 106} 107 108static void usbtv_disconnect(struct usb_interface *intf) 109{ 110 struct usbtv *usbtv = usb_get_intfdata(intf); 111 112 usb_set_intfdata(intf, NULL); 113 114 if (!usbtv) 115 return; 116 117 usbtv_audio_free(usbtv); 118 usbtv_video_free(usbtv); 119 120 usb_put_dev(usbtv->udev); 121 usbtv->udev = NULL; 122 123 /* the usbtv structure will be deallocated when v4l2 will be 124 done using it */ 125 v4l2_device_put(&usbtv->v4l2_dev); 126} 127 128static struct usb_device_id usbtv_id_table[] = { 129 { USB_DEVICE(0x1b71, 0x3002) }, 130 {} 131}; 132MODULE_DEVICE_TABLE(usb, usbtv_id_table); 133 134MODULE_AUTHOR("Lubomir Rintel, Federico Simoncelli"); 135MODULE_DESCRIPTION("Fushicai USBTV007 Audio-Video Grabber Driver"); 136MODULE_LICENSE("Dual BSD/GPL"); 137 138static struct usb_driver usbtv_usb_driver = { 139 .name = "usbtv", 140 .id_table = usbtv_id_table, 141 .probe = usbtv_probe, 142 .disconnect = usbtv_disconnect, 143}; 144 145module_usb_driver(usbtv_usb_driver); 146