├── README.md ├── Makefile ├── .gitignore ├── gvusb2-regs.h ├── gvusb2.h ├── LICENSE.bsd ├── gvusb2-core.c ├── gvusb2-vid.h ├── gvusb2-i2c.c ├── gvusb2-vid.c ├── gvusb2-snd.c ├── LICENSE.gpl └── gvusb2-v4l2.c /README.md: -------------------------------------------------------------------------------- 1 | GV-USB2 Linux Driver 2 | ==================== 3 | 4 | A linux driver for the IO-DATA GV-USB2 SD capture device. 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | obj-m += gvusb2-sound.o gvusb2-video.o 2 | 3 | gvusb2-sound-y := gvusb2-snd.o gvusb2-core.o 4 | gvusb2-video-y := gvusb2-vid.o gvusb2-v4l2.o gvusb2-core.o gvusb2-i2c.o 5 | 6 | all: 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 8 | 9 | clean: 10 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # custom stuff 55 | .vscode/ 56 | -------------------------------------------------------------------------------- /gvusb2-regs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ 2 | /* 3 | * Copyright (c) 2019 Isaac Lozano <109lozanoi@gmail.com> 4 | * 5 | * This code is released using a dual license strategy: BSD/GPL 6 | * You can choose the licence that better fits your requirements. 7 | * 8 | * Released under the terms of 3-clause BSD License 9 | * Released under the terms of GNU General Public License Version 2.0 10 | * 11 | */ 12 | 13 | #ifndef __GVUSB2_REGS_H__ 14 | #define __GVUSB2_REGS_H__ 15 | 16 | /* GPIO pins */ 17 | #define GVUSB2_GPIO_SDA_RESET 0x10 /* active low */ 18 | #define GVUSB2_GPIO_SOUND_ENABLE 0x20 19 | #define GVUSB2_GPIO_VDEC_RESET 0x08 /* active low */ 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /gvusb2.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ 2 | /* 3 | * Copyright (c) 2019 Isaac Lozano <109lozanoi@gmail.com> 4 | * 5 | * This code is released using a dual license strategy: BSD/GPL 6 | * You can choose the licence that better fits your requirements. 7 | * 8 | * Released under the terms of 3-clause BSD License 9 | * Released under the terms of GNU General Public License Version 2.0 10 | * 11 | */ 12 | 13 | #ifndef __GVUSB2_H__ 14 | #define __GVUSB2_H__ 15 | 16 | #include 17 | 18 | #define GVUSB2_NUM_URBS 4 19 | #define GVUSB2_NUM_ISOCH_PACKETS 0x100 20 | #define GVUSB2_MAX_AUDIO_PACKET_SIZE 0x100 21 | #define GVUSB2_MAX_VIDEO_PACKET_SIZE 0xc00 22 | #define GVUSB2_VENDOR_ID 0x04bb 23 | #define GVUSB2_PRODUCT_ID 0x0532 24 | 25 | #define gvusb2_dbg(dev, fmt, args...) \ 26 | dev_info(dev, fmt, ## args) 27 | 28 | struct gvusb2_dev { 29 | struct usb_device *udev; 30 | }; 31 | 32 | int gvusb2_read_reg(struct gvusb2_dev *dev, u16 reg, u8 *value); 33 | int gvusb2_write_reg(struct gvusb2_dev *dev, u16 reg, u8 value); 34 | int gvusb2_set_reg_mask(struct gvusb2_dev *dev, u16 reg, u8 mask, u8 value); 35 | int gvusb2_init(struct gvusb2_dev *dev, struct usb_device *udev); 36 | int gvusb2_free(struct gvusb2_dev *dev); 37 | 38 | int gvusb2_snd_reset_adc(struct gvusb2_dev *dev); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /LICENSE.bsd: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, Isaac Lozano 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of Isaac Lozano nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /gvusb2-core.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause 2 | /* 3 | * Copyright (c) 2019 Isaac Lozano <109lozanoi@gmail.com> 4 | * 5 | * This code is released using a dual license strategy: BSD/GPL 6 | * You can choose the licence that better fits your requirements. 7 | * 8 | * Released under the terms of 3-clause BSD License 9 | * Released under the terms of GNU General Public License Version 2.0 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "gvusb2.h" 18 | #include "gvusb2-regs.h" 19 | 20 | int gvusb2_read_reg(struct gvusb2_dev *dev, u16 reg, u8 *value) 21 | { 22 | int ret; 23 | int pipe = usb_rcvctrlpipe(dev->udev, 0); 24 | u8 *buf; 25 | 26 | buf = kmalloc(sizeof(u8), GFP_KERNEL); 27 | if (buf == NULL) 28 | return -ENOMEM; 29 | 30 | *value = 0; 31 | ret = usb_control_msg(dev->udev, pipe, 0x00, 32 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 33 | 0x00, reg, buf, sizeof(u8), HZ); 34 | if (ret < 0) { 35 | pr_err("gvusb2: read failed on reg 0x%04x (%d)\n", 36 | reg, ret); 37 | kfree(buf); 38 | return ret; 39 | } 40 | 41 | *value = *buf; 42 | 43 | kfree(buf); 44 | 45 | return 0; 46 | } 47 | 48 | int gvusb2_write_reg(struct gvusb2_dev *dev, u16 reg, u8 value) 49 | { 50 | int ret; 51 | int pipe = usb_sndctrlpipe(dev->udev, 0); 52 | 53 | ret = usb_control_msg(dev->udev, pipe, 0x01, 54 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 55 | value, reg, NULL, 0, HZ); 56 | if (ret < 0) { 57 | pr_err("gvusb2: write failed on reg 0x%04x (%d)\n", 58 | reg, ret); 59 | return ret; 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | int gvusb2_set_reg_mask(struct gvusb2_dev *dev, u16 reg, u8 mask, u8 value) 66 | { 67 | int ret; 68 | u8 reg_val; 69 | 70 | ret = gvusb2_read_reg(dev, reg, ®_val); 71 | if (ret < 0) 72 | return ret; 73 | 74 | gvusb2_write_reg(dev, reg, (reg_val & ~mask) | value); 75 | if (ret < 0) 76 | return ret; 77 | 78 | return 0; 79 | } 80 | 81 | int gvusb2_init(struct gvusb2_dev *dev, struct usb_device *udev) 82 | { 83 | dev->udev = udev; 84 | return 0; 85 | } 86 | 87 | int gvusb2_free(struct gvusb2_dev *dev) 88 | { 89 | /* nothing here, yet */ 90 | return 0; 91 | } 92 | 93 | int gvusb2_snd_reset_adc(struct gvusb2_dev *dev) 94 | { 95 | /* TODO: return errors */ 96 | 97 | /* set audio GPIO pins to output */ 98 | gvusb2_set_reg_mask(dev, 0x0002, 0x30, 0x30); 99 | gvusb2_set_reg_mask(dev, 0x0000, 0x30, 0x10); 100 | 101 | /* disable AC97 interface */ 102 | gvusb2_write_reg(dev, 0x0500, 0x00); 103 | /* enable I2S interface */ 104 | gvusb2_write_reg(dev, 0x050c, 0x01); 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /gvusb2-vid.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ 2 | /* 3 | * Copyright (c) 2019 Isaac Lozano <109lozanoi@gmail.com> 4 | * 5 | * This code is released using a dual license strategy: BSD/GPL 6 | * You can choose the licence that better fits your requirements. 7 | * 8 | * Released under the terms of 3-clause BSD License 9 | * Released under the terms of GNU General Public License Version 2.0 10 | * 11 | */ 12 | 13 | #ifndef __GVUSB2_VID_H__ 14 | #define __GVUSB2_VID_H__ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "gvusb2.h" 23 | 24 | #define GVUSB2_INPUT_COMPOSITE 0 25 | #define GVUSB2_INPUT_SVIDEO 1 26 | #define GVUSB2_INPUT_MAX_VAL 1 27 | 28 | #define GVUSB2_CID_BASE (V4L2_CID_USER_BASE | 0xf000) 29 | #define GVUSB2_CID_VERTICAL_START (GVUSB2_CID_BASE + 0) 30 | #define GVUSB2_CID_HORIZONTAL_START (GVUSB2_CID_BASE + 1) 31 | 32 | struct gvusb2_vb { 33 | struct vb2_v4l2_buffer vb; 34 | struct list_head list; 35 | int buf_pos; 36 | int line_pos; 37 | int field; 38 | }; 39 | 40 | struct gvusb2_vid { 41 | /* core data */ 42 | struct gvusb2_dev gv; 43 | 44 | /* usb data */ 45 | struct usb_interface *intf; 46 | struct usb_endpoint_descriptor *ep; 47 | struct urb *urbs[GVUSB2_NUM_URBS]; 48 | /* keeps track of packet seq */ 49 | unsigned char counter; 50 | 51 | /* i2c data */ 52 | struct i2c_adapter adap; 53 | struct i2c_client i2c_client; 54 | 55 | /* v4l2 data */ 56 | struct v4l2_device v4l2_dev; 57 | struct v4l2_subdev *sd_tw9910; 58 | struct video_device vdev; 59 | struct v4l2_ctrl_handler ctrl_handler; 60 | struct mutex v4l2_lock; 61 | unsigned int input_num; 62 | unsigned int sequence; 63 | v4l2_std_id standard; 64 | 65 | /* vb2 data */ 66 | struct vb2_queue vb2q; 67 | struct mutex vb2q_lock; 68 | struct list_head buf_list; 69 | spinlock_t buf_list_lock; 70 | struct gvusb2_vb *current_buf; 71 | }; 72 | 73 | /* provided by gvusb2-vid.c */ 74 | void gvusb2_release(struct v4l2_device *v4l2_dev); 75 | int gvusb2_vid_submit_urbs(struct gvusb2_vid *dev); 76 | void gvusb2_vid_cancel_urbs(struct gvusb2_vid *dev); 77 | 78 | /* provided by gvusb2-v4l2.c */ 79 | void get_resolution(struct gvusb2_vid *dev, int *width, int *height); 80 | void gvusb2_vid_clear_queue(struct gvusb2_vid *dev); 81 | int gvusb2_vb2_setup(struct gvusb2_vid *dev); 82 | int gvusb2_v4l2_register(struct gvusb2_vid *dev); 83 | void gvusb2_v4l2_unregister(struct gvusb2_vid *dev); 84 | int gvusb2_video_register(struct gvusb2_vid *dev); 85 | 86 | /* provided by gvusb2-i2c.c */ 87 | int gvusb2_i2c_register(struct gvusb2_vid *dev); 88 | int gvusb2_i2c_unregister(struct gvusb2_vid *dev); 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /gvusb2-i2c.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause 2 | /* 3 | * Copyright (c) 2019 Isaac Lozano <109lozanoi@gmail.com> 4 | * 5 | * This code is released using a dual license strategy: BSD/GPL 6 | * You can choose the licence that better fits your requirements. 7 | * 8 | * Released under the terms of 3-clause BSD License 9 | * Released under the terms of GNU General Public License Version 2.0 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "gvusb2.h" 18 | #include "gvusb2-vid.h" 19 | 20 | static int gvusb2_i2c_busy_wait(struct gvusb2_vid *dev, u8 wait_mask) 21 | { 22 | int attempts; 23 | u8 flag; 24 | 25 | attempts = 0; 26 | while (attempts < 100) { 27 | gvusb2_read_reg(&dev->gv, 0x0201, &flag); 28 | if (flag & wait_mask) 29 | return 0; 30 | } 31 | 32 | return -ETIMEDOUT; 33 | } 34 | 35 | int gvusb2_i2c_read_reg(struct gvusb2_vid *dev, u8 addr, u8 reg, u8 *value) 36 | { 37 | int ret; 38 | 39 | /* set i2c address */ 40 | ret = gvusb2_write_reg(&dev->gv, 0x0203, (addr << 1) | 1); 41 | if (ret < 0) 42 | return ret; 43 | 44 | /* set i2c sub-address */ 45 | ret = gvusb2_write_reg(&dev->gv, 0x0208, reg); 46 | if (ret < 0) 47 | return ret; 48 | 49 | /* start read */ 50 | ret = gvusb2_write_reg(&dev->gv, 0x0200, 0x60); 51 | if (ret < 0) 52 | return ret; 53 | 54 | /* wait for read to go through */ 55 | ret = gvusb2_i2c_busy_wait(dev, 0x01); 56 | if (ret < 0) 57 | return ret; 58 | 59 | ret = gvusb2_read_reg(&dev->gv, 0x0209, value); 60 | if (ret < 0) 61 | return ret; 62 | 63 | return 0; 64 | } 65 | 66 | int gvusb2_i2c_write_reg(struct gvusb2_vid *dev, u8 addr, u8 reg, u8 value) 67 | { 68 | int ret; 69 | 70 | /* set i2c address */ 71 | ret = gvusb2_write_reg(&dev->gv, 0x0203, addr << 1); 72 | if (ret < 0) 73 | return ret; 74 | 75 | /* set i2c sub-address */ 76 | ret = gvusb2_write_reg(&dev->gv, 0x0204, reg); 77 | if (ret < 0) 78 | return ret; 79 | 80 | /* set register value */ 81 | ret = gvusb2_write_reg(&dev->gv, 0x0205, value); 82 | if (ret < 0) 83 | return ret; 84 | 85 | /* start write */ 86 | ret = gvusb2_write_reg(&dev->gv, 0x0200, 0x05); 87 | if (ret < 0) 88 | return ret; 89 | 90 | /* wait for write to go through */ 91 | ret = gvusb2_i2c_busy_wait(dev, 0x04); 92 | if (ret < 0) 93 | return ret; 94 | 95 | return 0; 96 | } 97 | 98 | static int gvusb2_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], 99 | int num) 100 | { 101 | struct gvusb2_vid *dev = i2c_adap->algo_data; 102 | int ret, i; 103 | 104 | for (i = 0; i < num; i++) { 105 | dev_dbg(&dev->intf->dev, 106 | "gvusb2-i2c: addr=%02x", msgs[i].addr); 107 | 108 | if (i + 1 < num && msgs[i].len == 1 && 109 | ((msgs[i].flags & I2C_M_RD) == 0) && 110 | (msgs[i + 1].flags & I2C_M_RD) && 111 | msgs[i].addr == msgs[i + 1].addr) { 112 | dev_dbg(&dev->intf->dev, 113 | " subaddr=%02x", msgs[i].buf[0]); 114 | 115 | ret = gvusb2_i2c_read_reg(dev, msgs[i].addr, 116 | msgs[i].buf[0], msgs[i + 1].buf); 117 | if (ret < 0) { 118 | dev_dbg(&dev->intf->dev, " ERR (%d)\n", ret); 119 | return ret; 120 | } 121 | 122 | dev_dbg(&dev->intf->dev, 123 | " read=%02x\n", msgs[i + 1].buf[0]); 124 | 125 | i++; 126 | } else if (msgs[i].len == 2) { 127 | dev_dbg(&dev->intf->dev, " subaddr=%02x write=%02x\n", 128 | msgs[i].buf[0], msgs[i].buf[1]); 129 | 130 | ret = gvusb2_i2c_write_reg(dev, msgs[i].addr, 131 | msgs[i].buf[0], msgs[i].buf[1]); 132 | if (ret < 0) { 133 | dev_dbg(&dev->intf->dev, " ERR (%d)\n", ret); 134 | return ret; 135 | } 136 | } else { 137 | dev_dbg(&dev->intf->dev, " EOPNOTSUPP\n"); 138 | return -EOPNOTSUPP; 139 | } 140 | } 141 | 142 | return num; 143 | } 144 | 145 | static u32 gvusb2_i2c_functionality(struct i2c_adapter *adap) 146 | { 147 | return I2C_FUNC_SMBUS_BYTE_DATA; 148 | } 149 | 150 | static const struct i2c_algorithm gvusb2_i2c_algo = { 151 | .master_xfer = gvusb2_i2c_xfer, 152 | .functionality = gvusb2_i2c_functionality, 153 | }; 154 | 155 | int gvusb2_i2c_register(struct gvusb2_vid *dev) 156 | { 157 | int ret; 158 | struct i2c_adapter *adap = &dev->adap; 159 | struct i2c_client *client = &dev->i2c_client; 160 | 161 | adap->owner = THIS_MODULE; 162 | adap->algo = &gvusb2_i2c_algo; 163 | adap->dev.parent = &dev->intf->dev; 164 | strscpy(adap->name, "gvusb2", sizeof(adap->name)); 165 | /* maybe set this to just dev? */ 166 | adap->algo_data = dev; 167 | 168 | /* is this needed? */ 169 | //i2c_set_adapdata(adap, &dev->v4l2_dev); 170 | 171 | ret = i2c_add_adapter(adap); 172 | if (ret < 0) 173 | return ret; 174 | 175 | /* for debugging */ 176 | strscpy(client->name, "gvusb2 internal", sizeof(client->name)); 177 | client->adapter = adap; 178 | client->addr = 0x44; 179 | 180 | /* set i2c clock divider */ 181 | gvusb2_write_reg(&dev->gv, 0x0202, 0x08); 182 | 183 | /* disable alternate i2c */ 184 | gvusb2_write_reg(&dev->gv, 0x02ff, 0x00); 185 | 186 | return 0; 187 | } 188 | 189 | int gvusb2_i2c_unregister(struct gvusb2_vid *dev) 190 | { 191 | i2c_del_adapter(&dev->adap); 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /gvusb2-vid.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause 2 | /* 3 | * Copyright (c) 2019 Isaac Lozano <109lozanoi@gmail.com> 4 | * 5 | * This code is released using a dual license strategy: BSD/GPL 6 | * You can choose the licence that better fits your requirements. 7 | * 8 | * Released under the terms of 3-clause BSD License 9 | * Released under the terms of GNU General Public License Version 2.0 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "gvusb2-vid.h" 19 | 20 | MODULE_DESCRIPTION("gvusb2 video driver"); 21 | MODULE_AUTHOR("Isaac Lozano <109lozanoi@gmail.com>"); 22 | MODULE_LICENSE("Dual BSD/GPL"); 23 | 24 | static const struct usb_device_id gvusb2_id_table[] = { 25 | { USB_DEVICE(GVUSB2_VENDOR_ID, GVUSB2_PRODUCT_ID) }, 26 | { } 27 | }; 28 | MODULE_DEVICE_TABLE(usb, gvusb2_id_table); 29 | 30 | /***************************************************************************** 31 | * Data Processing Functions 32 | ****************************************************************************/ 33 | 34 | static inline 35 | struct gvusb2_vb *gvusb2_vid_next_buffer(struct gvusb2_vid *dev) 36 | { 37 | struct gvusb2_vb *buf = NULL; 38 | unsigned long flags; 39 | 40 | WARN_ON(dev->current_buf); 41 | 42 | spin_lock_irqsave(&dev->buf_list_lock, flags); 43 | 44 | if (!list_empty(&dev->buf_list)) { 45 | buf = list_first_entry(&dev->buf_list, struct gvusb2_vb, list); 46 | list_del(&buf->list); 47 | } 48 | 49 | spin_unlock_irqrestore(&dev->buf_list_lock, flags); 50 | 51 | return buf; 52 | } 53 | 54 | static inline 55 | void gvusb2_vid_copy_video(struct gvusb2_vid *dev, u8 *buf, int len) 56 | { 57 | int bytes_per_line, width; 58 | struct gvusb2_vb *vb = dev->current_buf; 59 | u32 buffer_len = vb->vb.vb2_buf.planes[0].length; 60 | u8 *buffer_addr = vb2_plane_vaddr(&vb->vb.vb2_buf, 0); 61 | 62 | get_resolution(dev, &width, 0); 63 | bytes_per_line = width * 2; 64 | 65 | while (len > 0) { 66 | int bytes_left_in_line = bytes_per_line - vb->line_pos; 67 | int len_to_copy; 68 | 69 | if (len < bytes_left_in_line) 70 | len_to_copy = len; 71 | else 72 | len_to_copy = bytes_left_in_line; 73 | 74 | if (vb->buf_pos + len_to_copy > buffer_len) { 75 | dev_warn(&dev->intf->dev, 76 | "buffer overflow detected.\n"); 77 | 78 | /* this seems to break it somehow? */ 79 | // memcpy(vb2_plane_vaddr(&vb->vb.vb2_buf, 0) + vb->buf_pos, 80 | // buf, vb->vb.vb2_buf.planes[0].length - vb->buf_pos); 81 | return; 82 | } 83 | 84 | memcpy(buffer_addr + vb->buf_pos, buf, len_to_copy); 85 | vb->buf_pos += len_to_copy; 86 | vb->line_pos += len_to_copy; 87 | len -= len_to_copy; 88 | buf += len_to_copy; 89 | 90 | if (vb->line_pos == bytes_per_line) { 91 | vb->buf_pos += bytes_per_line; 92 | vb->line_pos = 0; 93 | } 94 | } 95 | } 96 | 97 | static inline void gvusb2_vid_submit_video_buffer(struct gvusb2_vid *dev) 98 | { 99 | struct gvusb2_vb *vb = dev->current_buf; 100 | 101 | /* submit buffer */ 102 | /* TODO: Do we set this even if it's too small? */ 103 | vb2_set_plane_payload(&vb->vb.vb2_buf, 0, 104 | vb->vb.vb2_buf.planes[0].length); 105 | 106 | vb->vb.sequence = dev->sequence++; 107 | vb->vb.field = V4L2_FIELD_INTERLACED; 108 | vb->vb.vb2_buf.timestamp = ktime_get_ns(); 109 | vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE); 110 | 111 | dev->current_buf = NULL; 112 | 113 | /* get a new buffer */ 114 | dev->current_buf = gvusb2_vid_next_buffer(dev); 115 | } 116 | 117 | static inline 118 | void gvusb2_vid_process_status_packet(struct gvusb2_vid *dev, u8 status_byte) 119 | { 120 | if (dev->current_buf == NULL) { 121 | dev->current_buf = gvusb2_vid_next_buffer(dev); 122 | return; 123 | } 124 | 125 | if (status_byte & 0x40) { 126 | /* odd field */ 127 | gvusb2_vid_submit_video_buffer(dev); 128 | } else { 129 | /* even field */ 130 | int width; 131 | 132 | get_resolution(dev, &width, 0); 133 | dev->current_buf->buf_pos = width * 2; 134 | dev->current_buf->line_pos = 0; 135 | 136 | if (dev->current_buf->field == 1) { 137 | gvusb2_vid_submit_video_buffer(dev); 138 | } else { 139 | dev->current_buf->field = 1; 140 | } 141 | } 142 | } 143 | 144 | static inline 145 | void gvusb2_vid_process_data(struct gvusb2_vid *dev, u8 *buf, int len) 146 | { 147 | if (len < 4) { 148 | gvusb2_dbg(&dev->intf->dev, "video packet too small\n"); 149 | return; 150 | } 151 | 152 | if (buf[0] & 0x80) { 153 | /* Status packet */ 154 | dev->counter = (dev->counter + 1) % 64; 155 | 156 | gvusb2_vid_process_status_packet(dev, buf[0]); 157 | } else { 158 | /* Data packet */ 159 | if (dev->counter != buf[1]) 160 | gvusb2_dbg(&dev->intf->dev, 161 | "counter desync. expected %d got %d\n", 162 | dev->counter, buf[1]); 163 | 164 | dev->counter = (buf[1] + 1) % 64; 165 | 166 | if (dev->current_buf != NULL) 167 | gvusb2_vid_copy_video(dev, buf + 4, len - 4); 168 | } 169 | 170 | } 171 | 172 | static inline 173 | void gvusb2_vid_process_isoc(struct gvusb2_vid *dev, struct urb *urb) 174 | { 175 | int i; 176 | 177 | for (i = 0; i < urb->number_of_packets; i++) { 178 | int status = urb->iso_frame_desc[i].status; 179 | 180 | if (status < 0) { 181 | gvusb2_dbg(&dev->intf->dev, 182 | "iso packet failed, skipping (%d)\n", status); 183 | } else { 184 | u8 *data = urb->transfer_buffer + 185 | urb->iso_frame_desc[i].offset; 186 | int len = urb->iso_frame_desc[i].actual_length; 187 | 188 | gvusb2_vid_process_data(dev, data, len); 189 | } 190 | } 191 | } 192 | 193 | static void gvusb2_vid_isoc_irq(struct urb *urb) 194 | { 195 | int i, ret; 196 | struct gvusb2_vid *dev = urb->context; 197 | 198 | switch (urb->status) { 199 | case 0: 200 | break; 201 | case -ECONNRESET: 202 | case -ENOENT: 203 | case -ESHUTDOWN: 204 | return; 205 | default: 206 | gvusb2_dbg(&dev->intf->dev, 207 | "urb error! status %d\n", urb->status); 208 | return; 209 | } 210 | 211 | gvusb2_vid_process_isoc(dev, urb); 212 | 213 | for (i = 0; i < urb->number_of_packets; i++) { 214 | urb->iso_frame_desc[i].status = 0; 215 | urb->iso_frame_desc[i].actual_length = 0; 216 | } 217 | 218 | ret = usb_submit_urb(urb, GFP_ATOMIC); 219 | if (ret) 220 | gvusb2_dbg(&dev->intf->dev, "urb resubmit failed (%d)\n", ret); 221 | } 222 | 223 | /***************************************************************************** 224 | * USB functions 225 | ****************************************************************************/ 226 | 227 | void gvusb2_vid_free_urbs(struct gvusb2_vid *dev) 228 | { 229 | int i; 230 | 231 | for (i = 0; i < GVUSB2_NUM_URBS; i++) { 232 | struct urb *urb = dev->urbs[i]; 233 | 234 | if (urb != NULL) { 235 | kfree(urb->transfer_buffer); 236 | 237 | usb_free_urb(urb); 238 | dev->urbs[i] = NULL; 239 | } 240 | } 241 | } 242 | 243 | int gvusb2_vid_allocate_urbs(struct gvusb2_vid *dev) 244 | { 245 | int i; 246 | 247 | for (i = 0; i < GVUSB2_NUM_URBS; i++) { 248 | struct urb *urb; 249 | int total_offset, pidx; 250 | 251 | urb = usb_alloc_urb(GVUSB2_NUM_ISOCH_PACKETS, GFP_KERNEL); 252 | if (urb == NULL) { 253 | gvusb2_vid_free_urbs(dev); 254 | return -ENOMEM; 255 | } 256 | dev->urbs[i] = urb; 257 | 258 | urb->transfer_buffer = kzalloc( 259 | GVUSB2_NUM_ISOCH_PACKETS * GVUSB2_MAX_VIDEO_PACKET_SIZE, 260 | GFP_KERNEL); 261 | if (urb->transfer_buffer == NULL) { 262 | gvusb2_vid_free_urbs(dev); 263 | return -ENOMEM; 264 | } 265 | 266 | urb->dev = dev->gv.udev; 267 | urb->pipe = usb_rcvisocpipe(dev->gv.udev, 0x02); 268 | urb->transfer_buffer_length = 269 | GVUSB2_NUM_ISOCH_PACKETS * GVUSB2_MAX_VIDEO_PACKET_SIZE; 270 | urb->complete = gvusb2_vid_isoc_irq; 271 | urb->context = dev; 272 | urb->interval = 1; 273 | urb->start_frame = 0; 274 | urb->number_of_packets = GVUSB2_NUM_ISOCH_PACKETS; 275 | urb->transfer_flags = URB_ISO_ASAP; 276 | 277 | total_offset = 0; 278 | for (pidx = 0; pidx < GVUSB2_NUM_ISOCH_PACKETS; pidx++) { 279 | urb->iso_frame_desc[pidx].offset = total_offset; 280 | urb->iso_frame_desc[pidx].length = 281 | GVUSB2_MAX_VIDEO_PACKET_SIZE; 282 | total_offset += GVUSB2_MAX_VIDEO_PACKET_SIZE; 283 | } 284 | } 285 | 286 | return 0; 287 | } 288 | 289 | int gvusb2_vid_submit_urbs(struct gvusb2_vid *dev) 290 | { 291 | int i; 292 | int ret; 293 | 294 | for (i = 0; i < GVUSB2_NUM_URBS; i++) { 295 | ret = usb_submit_urb(dev->urbs[i], GFP_KERNEL); 296 | if (ret < 0) { 297 | gvusb2_dbg(&dev->intf->dev, 298 | "urb submit failed (%d)\n", ret); 299 | return ret; 300 | } 301 | } 302 | 303 | return 0; 304 | } 305 | 306 | void gvusb2_vid_cancel_urbs(struct gvusb2_vid *dev) 307 | { 308 | int i; 309 | 310 | for (i = 0; i < GVUSB2_NUM_URBS; i++) 311 | usb_kill_urb(dev->urbs[i]); 312 | } 313 | 314 | /***************************************************************************** 315 | * STK1150 control functions 316 | ****************************************************************************/ 317 | 318 | struct regval { 319 | u16 reg; 320 | u8 val; 321 | }; 322 | 323 | static void gvusb2_stk1150_reset_gpio(struct gvusb2_vid *dev) 324 | { 325 | /* set video decoder pin to output */ 326 | gvusb2_set_reg_mask(&dev->gv, 0x0002, 0x08, 0x08); 327 | /* set video decoder pin to high */ 328 | gvusb2_set_reg_mask(&dev->gv, 0x0000, 0x08, 0x08); 329 | } 330 | 331 | static void gvusb2_stk1150_init_inner(struct gvusb2_vid *dev) 332 | { 333 | int i; 334 | 335 | static const struct regval phase3[] = { 336 | {0x000d, 0x00}, 337 | {0x000f, 0x00}, 338 | {0x0018, 0x10}, 339 | {0x001b, 0x0e}, 340 | {0x001c, 0x46}, 341 | {0x001a, 0x14}, 342 | {0x0019, 0x00}, 343 | {0x0300, 0x12}, 344 | {0x0350, 0x41}, 345 | {0x0351, 0x00}, 346 | {0x0352, 0x00}, 347 | {0x0353, 0x00}, 348 | {0x0300, 0x80}, 349 | {0x0018, 0x10}, 350 | {0x0103, 0x00}, 351 | //{0x0110, 0x03}, 352 | //{0x0111, 0x00}, 353 | //{0x0112, 0x02}, 354 | //{0x0113, 0x00}, 355 | //{0x0114, 0xa3}, 356 | //{0x0115, 0x05}, 357 | //{0x0116, 0xf2}, 358 | //{0x0117, 0x00}, 359 | {0x0100, 0x33}, 360 | {0x0202, 0x08}, 361 | 362 | {0xffff, 0xff} 363 | }; 364 | 365 | for (i = 0; phase3[i].reg != 0xffff; i++) 366 | gvusb2_write_reg(&dev->gv, phase3[i].reg, phase3[i].val); 367 | } 368 | 369 | static void gvusb2_stk1150_reset_slave_ics(struct gvusb2_vid *dev) 370 | { 371 | u8 reg_0000; 372 | 373 | gvusb2_read_reg(&dev->gv, 0x0000, ®_0000); 374 | 375 | /* toggle video decoder slave reset pins via GPIO */ 376 | gvusb2_write_reg(&dev->gv, 0x0000, reg_0000 & 0xf7); 377 | usleep_range(10 * USEC_PER_MSEC, 20 * USEC_PER_MSEC); 378 | gvusb2_write_reg(&dev->gv, 0x0000, (reg_0000 & 0xf7) | 0x08); 379 | usleep_range(10 * USEC_PER_MSEC, 20 * USEC_PER_MSEC); 380 | } 381 | 382 | static void gvusb2_stk1150_init(struct gvusb2_vid *dev) 383 | { 384 | gvusb2_stk1150_reset_gpio(dev); 385 | gvusb2_stk1150_reset_slave_ics(dev); 386 | gvusb2_stk1150_init_inner(dev); 387 | } 388 | 389 | /***************************************************************************** 390 | * Driver functions 391 | ****************************************************************************/ 392 | 393 | static void gvusb2_vid_check_altsetting(struct usb_interface *intf, int i, 394 | struct usb_endpoint_descriptor **video_ep) 395 | { 396 | int ep; 397 | int num_endpoints = intf->altsetting[i].desc.bNumEndpoints; 398 | 399 | *video_ep = NULL; 400 | 401 | for (ep = 0; ep < num_endpoints; ep++) { 402 | struct usb_endpoint_descriptor *e = 403 | &intf->altsetting[i].endpoint[ep].desc; 404 | 405 | if (usb_endpoint_dir_in(e) && 406 | e->bEndpointAddress == 0x82 && 407 | usb_endpoint_xfer_isoc(e) && 408 | /* this corresponds to max 0xc00 bytes */ 409 | e->wMaxPacketSize == 0x1400) { 410 | *video_ep = e; 411 | gvusb2_dbg(&intf->dev, 412 | "found video at altsetting %d endpoint %d\n", 413 | i, ep); 414 | } 415 | } 416 | } 417 | 418 | int gvusb2_vid_free(struct gvusb2_vid *dev) 419 | { 420 | /* free urbs */ 421 | gvusb2_vid_free_urbs(dev); 422 | 423 | /* free gvusb2 */ 424 | gvusb2_free(&dev->gv); 425 | 426 | /* free me */ 427 | kfree(dev); 428 | 429 | return 0; 430 | } 431 | 432 | void gvusb2_release(struct v4l2_device *v4l2_dev) 433 | { 434 | struct gvusb2_vid *dev = 435 | container_of(v4l2_dev, struct gvusb2_vid, v4l2_dev); 436 | 437 | gvusb2_i2c_unregister(dev); 438 | 439 | v4l2_ctrl_handler_free(&dev->ctrl_handler); 440 | v4l2_device_unregister(&dev->v4l2_dev); 441 | 442 | mutex_destroy(&dev->v4l2_lock); 443 | mutex_destroy(&dev->vb2q_lock); 444 | 445 | gvusb2_vid_free(dev); 446 | } 447 | 448 | int gvusb2_vid_probe(struct usb_interface *intf, const struct usb_device_id *id) 449 | { 450 | struct usb_device *udev; 451 | struct gvusb2_vid *dev; 452 | int i, ret; 453 | struct usb_endpoint_descriptor *video_ep = NULL; 454 | 455 | udev = interface_to_usbdev(intf); 456 | 457 | /* check if we're on the video interface */ 458 | for (i = 0; i < intf->num_altsetting; i++) { 459 | gvusb2_vid_check_altsetting(intf, i, &video_ep); 460 | if (video_ep != NULL) 461 | break; 462 | } 463 | 464 | /* if we don't have a video device, we don't accept */ 465 | if (video_ep == NULL) 466 | return -ENODEV; 467 | 468 | /* allocate our driver data */ 469 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); 470 | if (dev == NULL) 471 | return -ENOMEM; 472 | 473 | /* initialize gvusb2 core stuff */ 474 | ret = gvusb2_init(&dev->gv, udev); 475 | if (ret < 0) 476 | goto free_dev; 477 | 478 | /* XXX: No hardcoding here. */ 479 | ret = usb_set_interface(udev, 0, 5); 480 | if (ret < 0) 481 | goto free_gvusb2; 482 | 483 | /* initialize gvusb2_vid data */ 484 | dev->ep = video_ep; 485 | dev->intf = intf; 486 | 487 | /* initialize the stk1150 in the gvusb2 */ 488 | gvusb2_stk1150_init(dev); 489 | 490 | /* allocate URBs */ 491 | gvusb2_vid_allocate_urbs(dev); 492 | if (ret < 0) 493 | goto free_gvusb2; 494 | 495 | /* initialize i2c data */ 496 | ret = gvusb2_i2c_register(dev); 497 | if (ret < 0) 498 | goto free_urbs; 499 | 500 | /* initialize video stuff */ 501 | ret = gvusb2_vb2_setup(dev); 502 | if (ret < 0) 503 | goto unregister_i2c; 504 | ret = gvusb2_v4l2_register(dev); 505 | if (ret < 0) 506 | goto unregister_i2c; 507 | ret = gvusb2_video_register(dev); 508 | if (ret < 0) 509 | goto unregister_v4l2; 510 | 511 | /* attach our data to the interface */ 512 | usb_set_intfdata(intf, dev); 513 | 514 | return 0; 515 | 516 | unregister_v4l2: 517 | gvusb2_v4l2_unregister(dev); 518 | unregister_i2c: 519 | gvusb2_i2c_unregister(dev); 520 | free_urbs: 521 | gvusb2_vid_free_urbs(dev); 522 | free_gvusb2: 523 | gvusb2_free(&dev->gv); 524 | free_dev: 525 | kfree(dev); 526 | 527 | return ret; 528 | } 529 | 530 | void gvusb2_vid_disconnect(struct usb_interface *intf) 531 | { 532 | struct gvusb2_vid *dev; 533 | 534 | /* remove our data from the interface */ 535 | dev = usb_get_intfdata(intf); 536 | usb_set_intfdata(intf, NULL); 537 | 538 | mutex_lock(&dev->vb2q_lock); 539 | mutex_lock(&dev->v4l2_lock); 540 | 541 | /* cancel urbs */ 542 | gvusb2_vid_cancel_urbs(dev); 543 | gvusb2_vid_free_urbs(dev); 544 | 545 | /* clear buffer list queue */ 546 | gvusb2_vid_clear_queue(dev); 547 | 548 | /* clean up v4l2 */ 549 | video_unregister_device(&dev->vdev); 550 | v4l2_device_disconnect(&dev->v4l2_dev); 551 | 552 | /* make udev NULL? */ 553 | 554 | mutex_unlock(&dev->v4l2_lock); 555 | mutex_unlock(&dev->vb2q_lock); 556 | 557 | /* decrease v4l2 refcount */ 558 | v4l2_device_put(&dev->v4l2_dev); 559 | } 560 | 561 | static struct usb_driver gvusb2_vid_usb_driver = { 562 | .name = "gvusb2-vid", 563 | .probe = gvusb2_vid_probe, 564 | .disconnect = gvusb2_vid_disconnect, 565 | .id_table = gvusb2_id_table, 566 | }; 567 | 568 | module_usb_driver(gvusb2_vid_usb_driver); 569 | -------------------------------------------------------------------------------- /gvusb2-snd.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause 2 | /* 3 | * Copyright (c) 2019 Isaac Lozano <109lozanoi@gmail.com> 4 | * 5 | * This code is released using a dual license strategy: BSD/GPL 6 | * You can choose the licence that better fits your requirements. 7 | * 8 | * Released under the terms of 3-clause BSD License 9 | * Released under the terms of GNU General Public License Version 2.0 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "gvusb2.h" 21 | 22 | #define CARD_NAME "gvusb2" 23 | 24 | MODULE_DESCRIPTION("gvusb2 sound driver"); 25 | MODULE_AUTHOR("Isaac Lozano <109lozanoi@gmail.com>"); 26 | MODULE_LICENSE("Dual BSD/GPL"); 27 | 28 | int index; 29 | char *id; 30 | bool enable; 31 | 32 | module_param(index, int, 0444); 33 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); 34 | module_param(id, charp, 0444); 35 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); 36 | module_param(enable, bool, 0444); 37 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); 38 | 39 | static const struct usb_device_id gvusb2_id_table[] = { 40 | { USB_DEVICE(GVUSB2_VENDOR_ID, GVUSB2_PRODUCT_ID) }, 41 | { } 42 | }; 43 | MODULE_DEVICE_TABLE(usb, gvusb2_id_table); 44 | 45 | struct gvusb2_snd { 46 | struct gvusb2_dev gv; 47 | struct usb_interface *intf; 48 | struct usb_endpoint_descriptor *ep; 49 | 50 | /* urb */ 51 | struct urb *urbs[GVUSB2_NUM_URBS]; 52 | 53 | /* alsa */ 54 | struct snd_card *card; 55 | struct snd_pcm *pcm; 56 | struct snd_pcm_substream *substream; 57 | int dma_offset; 58 | int avail; 59 | int hw_ptr; 60 | spinlock_t lock; 61 | }; 62 | 63 | static struct snd_pcm_hardware gvusb2_snd_hw = { 64 | .info = (SNDRV_PCM_INFO_MMAP | 65 | SNDRV_PCM_INFO_INTERLEAVED | 66 | SNDRV_PCM_INFO_BLOCK_TRANSFER | 67 | SNDRV_PCM_INFO_MMAP_VALID), 68 | .formats = SNDRV_PCM_FMTBIT_S16_LE, 69 | .rates = SNDRV_PCM_RATE_48000, 70 | .rate_min = 48000, 71 | .rate_max = 48000, 72 | .channels_min = 2, 73 | .channels_max = 2, 74 | .buffer_bytes_max = (128 * 1024), 75 | .period_bytes_min = 0xc000, 76 | .period_bytes_max = (128 * 1024), 77 | .periods_min = 1, 78 | .periods_max = 32, 79 | }; 80 | 81 | /* predefines */ 82 | static int gvusb2_snd_submit_isoc(struct gvusb2_snd *dev); 83 | static void gvusb2_snd_cancel_isoc(struct gvusb2_snd *dev); 84 | 85 | /***************************************************************************** 86 | * Alsa Stuff 87 | ****************************************************************************/ 88 | 89 | void gvusb2_snd_process_pcm( 90 | struct gvusb2_snd *dev, 91 | unsigned char *buf, 92 | unsigned int len) 93 | { 94 | unsigned long flags; 95 | struct snd_pcm_runtime *runtime = dev->substream->runtime; 96 | int frames = bytes_to_frames(runtime, len); 97 | 98 | spin_lock_irqsave(&dev->lock, flags); 99 | dev->hw_ptr += frames; 100 | if (dev->hw_ptr >= runtime->buffer_size) 101 | dev->hw_ptr -= runtime->buffer_size; 102 | 103 | dev->avail += frames; 104 | spin_unlock_irqrestore(&dev->lock, flags); 105 | 106 | if (dev->dma_offset + len > runtime->dma_bytes) { 107 | int len_to_copy = runtime->dma_bytes - dev->dma_offset; 108 | 109 | memcpy(runtime->dma_area + dev->dma_offset, buf, len_to_copy); 110 | 111 | len -= len_to_copy; 112 | buf += len_to_copy; 113 | dev->dma_offset = 0; 114 | } 115 | 116 | memcpy(runtime->dma_area + dev->dma_offset, buf, len); 117 | dev->dma_offset += len; 118 | 119 | spin_lock_irqsave(&dev->lock, flags); 120 | if (dev->avail >= runtime->period_size) { 121 | dev->avail -= runtime->period_size; 122 | spin_unlock_irqrestore(&dev->lock, flags); 123 | snd_pcm_period_elapsed(dev->substream); 124 | return; 125 | } 126 | spin_unlock_irqrestore(&dev->lock, flags); 127 | } 128 | 129 | static int gvusb2_snd_capture_open(struct snd_pcm_substream *substream) 130 | { 131 | int ret; 132 | unsigned long flags; 133 | struct gvusb2_snd *dev = snd_pcm_substream_chip(substream); 134 | struct snd_pcm_runtime *runtime = substream->runtime; 135 | 136 | ret = gvusb2_snd_submit_isoc(dev); 137 | if (ret < 0) 138 | return ret; 139 | 140 | spin_lock_irqsave(&dev->lock, flags); 141 | if (dev->substream == NULL) { 142 | dev->substream = substream; 143 | runtime->hw = gvusb2_snd_hw; 144 | ret = 0; 145 | } else { 146 | ret = -EBUSY; 147 | } 148 | spin_unlock_irqrestore(&dev->lock, flags); 149 | 150 | return ret; 151 | } 152 | 153 | static int gvusb2_snd_capture_close(struct snd_pcm_substream *substream) 154 | { 155 | struct gvusb2_snd *dev = snd_pcm_substream_chip(substream); 156 | 157 | dev->substream = NULL; 158 | gvusb2_snd_cancel_isoc(dev); 159 | 160 | return 0; 161 | } 162 | 163 | static int gvusb2_snd_hw_params( 164 | struct snd_pcm_substream *substream, 165 | struct snd_pcm_hw_params *hw_params) 166 | { 167 | unsigned int bytes; 168 | 169 | bytes = params_buffer_bytes(hw_params); 170 | if (substream->runtime->dma_bytes > 0) 171 | vfree(substream->runtime->dma_area); 172 | 173 | substream->runtime->dma_bytes = 0; 174 | substream->runtime->dma_area = vmalloc(bytes); 175 | if (substream->runtime->dma_area == NULL) 176 | return -ENOMEM; 177 | 178 | substream->runtime->dma_bytes = bytes; 179 | 180 | return 0; 181 | } 182 | 183 | static int gvusb2_snd_hw_free(struct snd_pcm_substream *substream) 184 | { 185 | if (substream->runtime->dma_bytes > 0) 186 | vfree(substream->runtime->dma_area); 187 | 188 | substream->runtime->dma_bytes = 0; 189 | 190 | return 0; 191 | } 192 | 193 | static int gvusb2_snd_pcm_prepare(struct snd_pcm_substream *substream) 194 | { 195 | /* TODO: Do we need this? */ 196 | return 0; 197 | } 198 | 199 | /* NOTE: THIS IS ATOMIC */ 200 | static int gvusb2_snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 201 | { 202 | struct gvusb2_snd *dev = snd_pcm_substream_chip(substream); 203 | 204 | switch (cmd) { 205 | case SNDRV_PCM_TRIGGER_START: 206 | return 0; 207 | case SNDRV_PCM_TRIGGER_STOP: 208 | dev->dma_offset = 0; 209 | dev->hw_ptr = 0; 210 | dev->avail = 0; 211 | return 0; 212 | default: 213 | return -EINVAL; 214 | } 215 | 216 | return 0; 217 | } 218 | 219 | /* NOTE: THIS IS ATOMIC */ 220 | static snd_pcm_uframes_t gvusb2_snd_pcm_pointer( 221 | struct snd_pcm_substream *substream) 222 | { 223 | struct gvusb2_snd *dev = snd_pcm_substream_chip(substream); 224 | 225 | return dev->hw_ptr; 226 | } 227 | 228 | static struct page *gvusb2_snd_pcm_page( 229 | struct snd_pcm_substream *substream, 230 | unsigned long offset) 231 | { 232 | return vmalloc_to_page(substream->runtime->dma_area + offset); 233 | } 234 | 235 | static int gvusb2_snd_dev_free(struct snd_device *device) 236 | { 237 | /* deallocate all sound card device stuff */ 238 | /* TODO: do we need this? */ 239 | 240 | return 0; 241 | } 242 | 243 | static struct snd_device_ops gvusb2_snd_device_ops = { 244 | .dev_free = gvusb2_snd_dev_free, 245 | }; 246 | 247 | static const struct snd_pcm_ops gvusb2_snd_capture_ops = { 248 | .open = gvusb2_snd_capture_open, 249 | .close = gvusb2_snd_capture_close, 250 | .ioctl = snd_pcm_lib_ioctl, 251 | .hw_params = gvusb2_snd_hw_params, 252 | .hw_free = gvusb2_snd_hw_free, 253 | .prepare = gvusb2_snd_pcm_prepare, 254 | .trigger = gvusb2_snd_pcm_trigger, 255 | .pointer = gvusb2_snd_pcm_pointer, 256 | .page = gvusb2_snd_pcm_page, 257 | }; 258 | 259 | int gvusb2_snd_alsa_init(struct gvusb2_snd *dev) 260 | { 261 | int ret; 262 | 263 | spin_lock_init(&dev->lock); 264 | dev->hw_ptr = dev->dma_offset = dev->avail = 0; 265 | 266 | ret = snd_card_new(&dev->intf->dev, index, id, THIS_MODULE, 0, 267 | &dev->card); 268 | if (ret < 0) 269 | return ret; 270 | 271 | ret = snd_device_new(dev->card, SNDRV_DEV_LOWLEVEL, dev, 272 | &gvusb2_snd_device_ops); 273 | if (ret < 0) { 274 | snd_card_free(dev->card); 275 | return ret; 276 | } 277 | 278 | ret = snd_pcm_new(dev->card, "analog in", 0, 0, 1, &dev->pcm); 279 | if (ret < 0) { 280 | snd_card_free(dev->card); 281 | return ret; 282 | } 283 | 284 | dev->pcm->private_data = dev; 285 | 286 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 287 | &gvusb2_snd_capture_ops); 288 | 289 | strscpy(dev->card->shortname, "gvusb2", sizeof(dev->card->shortname)); 290 | strscpy(dev->card->longname, "gvusb2", sizeof(dev->card->longname)); 291 | strscpy(dev->card->driver, "gvusb2-snd", sizeof(dev->card->driver)); 292 | 293 | /* register the card */ 294 | ret = snd_card_register(dev->card); 295 | if (ret < 0) { 296 | snd_card_free(dev->card); 297 | return ret; 298 | } 299 | 300 | return 0; 301 | } 302 | 303 | static void gvusb2_snd_alsa_free(struct gvusb2_snd *dev) 304 | { 305 | snd_card_free_when_closed(dev->card); 306 | dev->card = NULL; 307 | } 308 | 309 | /***************************************************************************** 310 | * USB Stuff 311 | ****************************************************************************/ 312 | 313 | /* Do not call in atomic contexts */ 314 | void gvusb2_snd_cancel_isoc(struct gvusb2_snd *dev) 315 | { 316 | int i; 317 | 318 | for (i = 0; i < GVUSB2_NUM_URBS; i++) { 319 | struct urb *urb = dev->urbs[i]; 320 | 321 | if (urb != NULL) 322 | usb_kill_urb(dev->urbs[i]); 323 | } 324 | } 325 | 326 | void gvusb2_snd_free_isoc(struct gvusb2_snd *dev) 327 | { 328 | int i; 329 | 330 | for (i = 0; i < GVUSB2_NUM_URBS; i++) { 331 | struct urb *urb = dev->urbs[i]; 332 | 333 | if (urb != NULL) { 334 | if (urb->transfer_buffer != NULL) 335 | kfree(urb->transfer_buffer); 336 | usb_free_urb(urb); 337 | dev->urbs[i] = NULL; 338 | } 339 | } 340 | } 341 | 342 | void gvusb2_snd_process_isoc(struct gvusb2_snd *dev, struct urb *urb) 343 | { 344 | int i; 345 | unsigned char *buf_iter; 346 | 347 | if (dev->substream == NULL) { 348 | gvusb2_dbg(&dev->intf->dev, "substream is null, skipping processing\n"); 349 | return; 350 | } 351 | 352 | buf_iter = urb->transfer_buffer; 353 | for (i = 0; i < urb->number_of_packets; i++) { 354 | if (urb->iso_frame_desc[i].status < 0) { 355 | gvusb2_dbg(&dev->intf->dev, "bad iso packet. skipping.\n"); 356 | } else { 357 | gvusb2_snd_process_pcm(dev, 358 | buf_iter, urb->iso_frame_desc[i].actual_length); 359 | } 360 | 361 | buf_iter += urb->iso_frame_desc[i].length; 362 | } 363 | } 364 | 365 | static void gvusb2_snd_isoc_irq(struct urb *urb) 366 | { 367 | int i, ret; 368 | struct gvusb2_snd *dev = urb->context; 369 | 370 | switch (urb->status) { 371 | case 0: 372 | break; 373 | case -ECONNRESET: 374 | case -ENOENT: 375 | case -ESHUTDOWN: 376 | return; 377 | default: 378 | gvusb2_dbg(&dev->intf->dev, "urb error! status %d\n", 379 | urb->status); 380 | return; 381 | } 382 | 383 | gvusb2_snd_process_isoc(dev, urb); 384 | 385 | for (i = 0; i < urb->number_of_packets; i++) { 386 | urb->iso_frame_desc[i].status = 0; 387 | urb->iso_frame_desc[i].actual_length = 0; 388 | } 389 | 390 | ret = usb_submit_urb(urb, GFP_ATOMIC); 391 | if (ret) 392 | gvusb2_dbg(&dev->intf->dev, "urb resubmit failed (%d)\n", ret); 393 | } 394 | 395 | static int gvusb2_snd_submit_isoc(struct gvusb2_snd *dev) 396 | { 397 | int i, ret; 398 | 399 | for (i = 0; i < GVUSB2_NUM_URBS; i++) { 400 | ret = usb_submit_urb(dev->urbs[i], GFP_KERNEL); 401 | if (ret < 0) 402 | /* TODO: clean up */ 403 | gvusb2_dbg(&dev->intf->dev, 404 | "error submitting urb %d\n", ret); 405 | } 406 | 407 | return 0; 408 | } 409 | 410 | static int gvusb2_snd_allocate_urbs(struct gvusb2_snd *dev) 411 | { 412 | int i; 413 | 414 | for (i = 0; i < GVUSB2_NUM_URBS; i++) { 415 | struct urb *urb; 416 | int total_offset, pidx; 417 | 418 | urb = usb_alloc_urb(GVUSB2_NUM_ISOCH_PACKETS, GFP_KERNEL); 419 | if (urb == NULL) 420 | goto free_urbs; 421 | 422 | dev->urbs[i] = urb; 423 | 424 | urb->transfer_buffer = kzalloc( 425 | GVUSB2_NUM_ISOCH_PACKETS * GVUSB2_MAX_AUDIO_PACKET_SIZE, 426 | GFP_KERNEL); 427 | if (urb->transfer_buffer == NULL) 428 | goto free_urbs; 429 | 430 | urb->dev = dev->gv.udev; 431 | urb->pipe = usb_rcvisocpipe(dev->gv.udev, 0x04); 432 | urb->transfer_buffer_length = 433 | GVUSB2_NUM_ISOCH_PACKETS * GVUSB2_MAX_AUDIO_PACKET_SIZE; 434 | urb->complete = gvusb2_snd_isoc_irq; 435 | urb->context = dev; 436 | urb->interval = 1; 437 | urb->start_frame = 0; 438 | urb->number_of_packets = GVUSB2_NUM_ISOCH_PACKETS; 439 | urb->transfer_flags = URB_ISO_ASAP; 440 | 441 | total_offset = 0; 442 | for (pidx = 0; pidx < GVUSB2_NUM_ISOCH_PACKETS; pidx++) { 443 | urb->iso_frame_desc[pidx].offset = total_offset; 444 | urb->iso_frame_desc[pidx].length = 445 | GVUSB2_MAX_AUDIO_PACKET_SIZE; 446 | total_offset += GVUSB2_MAX_AUDIO_PACKET_SIZE; 447 | } 448 | } 449 | 450 | return 0; 451 | 452 | free_urbs: 453 | gvusb2_snd_free_isoc(dev); 454 | return -ENOMEM; 455 | } 456 | 457 | /***************************************************************************** 458 | * Driver Stuff 459 | ****************************************************************************/ 460 | 461 | int gvusb2_snd_probe(struct usb_interface *intf, const struct usb_device_id *id) 462 | { 463 | struct usb_device *udev; 464 | struct gvusb2_snd *dev; 465 | int i, ret; 466 | struct usb_endpoint_descriptor *audio_ep = NULL; 467 | 468 | udev = interface_to_usbdev(intf); 469 | 470 | /* 471 | * The GV-USB2 uses a proprietary audio transfer, but the chip has 472 | * support for the USB audio class, so let's reject it if we see it. 473 | */ 474 | if (intf->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) 475 | return -ENODEV; 476 | 477 | /* check if we're on the audio interface */ 478 | for (i = 0; i < intf->num_altsetting; i++) { 479 | int ep; 480 | int num_endpoints = intf->altsetting[i].desc.bNumEndpoints; 481 | 482 | for (ep = 0; ep < num_endpoints; ep++) { 483 | struct usb_endpoint_descriptor *e = 484 | &intf->altsetting[i].endpoint[ep].desc; 485 | if (usb_endpoint_dir_in(e) && 486 | e->bEndpointAddress == 0x84 && 487 | usb_endpoint_xfer_isoc(e) && 488 | e->wMaxPacketSize == 0x100) { 489 | audio_ep = e; 490 | gvusb2_dbg(&intf->dev, "found audio at altsetting %d endpoint %d\n", 491 | i, ep); 492 | } 493 | } 494 | } 495 | 496 | /* if we don't have an audio device, we don't accept */ 497 | if (audio_ep == NULL) 498 | return -ENODEV; 499 | 500 | /* allocate our driver data */ 501 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); 502 | if (dev == NULL) 503 | return -ENOMEM; 504 | 505 | /* initialize gvusb2 core stuff */ 506 | ret = gvusb2_init(&dev->gv, udev); 507 | if (ret < 0) 508 | goto free_dev; 509 | 510 | /* XXX: No hardcoding here. */ 511 | ret = usb_set_interface(udev, 2, 1); 512 | if (ret < 0) 513 | goto free_gvusb2; 514 | 515 | /* reset the adc */ 516 | ret = gvusb2_snd_reset_adc(&dev->gv); 517 | if (ret < 0) 518 | goto free_gvusb2; 519 | 520 | /* initialize gvusb2_snd data */ 521 | dev->ep = audio_ep; 522 | dev->intf = intf; 523 | 524 | /* initialize sound stuff */ 525 | ret = gvusb2_snd_alsa_init(dev); 526 | if (ret < 0) 527 | goto free_gvusb2; 528 | 529 | /* allocate URBs */ 530 | ret = gvusb2_snd_allocate_urbs(dev); 531 | if (ret < 0) 532 | goto free_alsa; 533 | 534 | /* attach our data to the interface */ 535 | usb_set_intfdata(intf, dev); 536 | 537 | return 0; 538 | 539 | free_alsa: 540 | gvusb2_snd_alsa_free(dev); 541 | 542 | free_gvusb2: 543 | gvusb2_free(&dev->gv); 544 | 545 | free_dev: 546 | kfree(dev); 547 | 548 | return ret; 549 | } 550 | 551 | void gvusb2_snd_disconnect(struct usb_interface *intf) 552 | { 553 | struct gvusb2_snd *dev; 554 | 555 | /* remove our data from the interface */ 556 | dev = usb_get_intfdata(intf); 557 | usb_set_intfdata(intf, NULL); 558 | 559 | /* free isoc urbs */ 560 | gvusb2_snd_free_isoc(dev); 561 | 562 | /* free the sound card */ 563 | gvusb2_snd_alsa_free(dev); 564 | 565 | /* free the internal gvusb2 device */ 566 | gvusb2_free(&dev->gv); 567 | 568 | /* free me */ 569 | kfree(dev); 570 | } 571 | 572 | static struct usb_driver gvusb2_snd_usb_driver = { 573 | .name = "gvusb2-snd", 574 | .probe = gvusb2_snd_probe, 575 | .disconnect = gvusb2_snd_disconnect, 576 | .id_table = gvusb2_id_table, 577 | }; 578 | 579 | module_usb_driver(gvusb2_snd_usb_driver); 580 | -------------------------------------------------------------------------------- /LICENSE.gpl: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /gvusb2-v4l2.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause 2 | /* 3 | * Copyright (c) 2019 Isaac Lozano <109lozanoi@gmail.com> 4 | * 5 | * This code is released using a dual license strategy: BSD/GPL 6 | * You can choose the licence that better fits your requirements. 7 | * 8 | * Released under the terms of 3-clause BSD License 9 | * Released under the terms of GNU General Public License Version 2.0 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "gvusb2-vid.h" 25 | 26 | /***************************************************************************** 27 | * Helper functions 28 | ****************************************************************************/ 29 | 30 | struct i2c_regval { 31 | u8 reg; 32 | u8 val; 33 | }; 34 | 35 | void get_resolution(struct gvusb2_vid *dev, int *width, int *height) 36 | { 37 | switch (dev->standard) { 38 | default: 39 | case V4L2_STD_NTSC_M: 40 | if (width != NULL) 41 | *width = 720; 42 | if (height != NULL) 43 | *height = 480; 44 | break; 45 | case V4L2_STD_PAL_B: 46 | if (width != NULL) 47 | *width = 720; 48 | if (height != NULL) 49 | *height = 576; 50 | break; 51 | } 52 | } 53 | 54 | void gvusb2_vid_clear_queue(struct gvusb2_vid *dev) 55 | { 56 | struct gvusb2_vb *buf; 57 | unsigned long flags; 58 | 59 | spin_lock_irqsave(&dev->buf_list_lock, flags); 60 | while (!list_empty(&dev->buf_list)) { 61 | buf = list_first_entry(&dev->buf_list, 62 | struct gvusb2_vb, list); 63 | list_del(&buf->list); 64 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 65 | } 66 | 67 | if (dev->current_buf) { 68 | vb2_buffer_done(&dev->current_buf->vb.vb2_buf, 69 | VB2_BUF_STATE_ERROR); 70 | dev->current_buf = NULL; 71 | } 72 | spin_unlock_irqrestore(&dev->buf_list_lock, flags); 73 | } 74 | 75 | /***************************************************************************** 76 | * Videobuf2 functions 77 | ****************************************************************************/ 78 | 79 | static int gvusb2_vb2_queue_setup(struct vb2_queue *vb2q, 80 | unsigned int *nbuffers, 81 | unsigned int *nplanes, 82 | unsigned int sizes[], 83 | struct device *alloc_devs[]) 84 | { 85 | struct gvusb2_vid *dev = vb2_get_drv_priv(vb2q); 86 | int width, height; 87 | unsigned long size; 88 | 89 | /* Size in bytes of a single frame */ 90 | /* 2 pixels is 4 bytes */ 91 | get_resolution(dev, &width, &height); 92 | size = width * height * 2; 93 | 94 | /* clamp buffers to how much we want */ 95 | if (*nbuffers < 4) 96 | *nbuffers = 4; 97 | 98 | /* the program is actually wanting to set up a queue */ 99 | if (*nplanes) { 100 | if (*nplanes != 1 || sizes[0] < size) 101 | return -EINVAL; 102 | return 0; 103 | } 104 | 105 | /* the program is asking what we want for a queue*/ 106 | /* answer with what we want */ 107 | *nplanes = 1; 108 | sizes[0] = size; 109 | 110 | return 0; 111 | } 112 | 113 | static void gvusb2_vb2_buf_queue(struct vb2_buffer *vb) 114 | { 115 | unsigned long flags; 116 | struct gvusb2_vid *dev = vb2_get_drv_priv(vb->vb2_queue); 117 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 118 | struct gvusb2_vb *gvusb2_vbuf = 119 | container_of(vbuf, struct gvusb2_vb, vb); 120 | 121 | spin_lock_irqsave(&dev->buf_list_lock, flags); 122 | 123 | gvusb2_vbuf->buf_pos = 0; 124 | gvusb2_vbuf->line_pos = 0; 125 | gvusb2_vbuf->field = 0; 126 | list_add_tail(&gvusb2_vbuf->list, &dev->buf_list); 127 | 128 | spin_unlock_irqrestore(&dev->buf_list_lock, flags); 129 | } 130 | 131 | static int gvusb2_vb2_start_streaming(struct vb2_queue *vb2q, 132 | unsigned int count) 133 | { 134 | int ret; 135 | struct gvusb2_vid *dev = vb2_get_drv_priv(vb2q); 136 | s32 reg_07; 137 | 138 | /* start mutex */ 139 | if (mutex_lock_interruptible(&dev->v4l2_lock)) 140 | return -ERESTARTSYS; 141 | 142 | /* set seq to 0 */ 143 | dev->sequence = 0; 144 | 145 | /* set cropping */ 146 | reg_07 = i2c_smbus_read_byte_data(&dev->i2c_client, 0x07); 147 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x07, reg_07 & 0x0f); 148 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x08, 0x13); 149 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x09, 0xf4); 150 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x0a, 0x12); 151 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x0b, 0xd2); 152 | 153 | /* start tw9910 */ 154 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); 155 | 156 | /* start gvusb2 */ 157 | gvusb2_write_reg(&dev->gv, 0x0100, 0xb3); 158 | /* probably don't need to set no VBI */ 159 | gvusb2_write_reg(&dev->gv, 0x0103, 0x00); 160 | 161 | /* submit urbs */ 162 | ret = gvusb2_vid_submit_urbs(dev); 163 | if (ret < 0) 164 | return ret; 165 | 166 | /* stop mutex */ 167 | mutex_unlock(&dev->v4l2_lock); 168 | 169 | return 0; 170 | } 171 | 172 | static void gvusb2_vb2_stop_streaming(struct vb2_queue *vb2q) 173 | { 174 | struct gvusb2_vid *dev = vb2_get_drv_priv(vb2q); 175 | 176 | /* start mutex */ 177 | if (mutex_lock_interruptible(&dev->v4l2_lock)) 178 | return; 179 | 180 | /* cancel urbs */ 181 | gvusb2_vid_cancel_urbs(dev); 182 | 183 | /* stop gvusb2 */ 184 | gvusb2_write_reg(&dev->gv, 0x0100, 0x33); 185 | /* probably don't need to set no VBI */ 186 | gvusb2_write_reg(&dev->gv, 0x0103, 0x00); 187 | 188 | /* stop tw9910 */ 189 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); 190 | 191 | /* clear queue */ 192 | gvusb2_vid_clear_queue(dev); 193 | 194 | /* unlok mutex */ 195 | mutex_unlock(&dev->v4l2_lock); 196 | } 197 | 198 | static const struct vb2_ops gvusb2_vb2_ops = { 199 | .queue_setup = gvusb2_vb2_queue_setup, 200 | .buf_queue = gvusb2_vb2_buf_queue, 201 | .start_streaming = gvusb2_vb2_start_streaming, 202 | .stop_streaming = gvusb2_vb2_stop_streaming, 203 | .wait_prepare = vb2_ops_wait_prepare, 204 | .wait_finish = vb2_ops_wait_finish, 205 | }; 206 | 207 | int gvusb2_vb2_setup(struct gvusb2_vid *dev) 208 | { 209 | int ret; 210 | struct vb2_queue *vb2q; 211 | 212 | /* init our vb2 lock */ 213 | mutex_init(&dev->vb2q_lock); 214 | 215 | vb2q = &dev->vb2q; 216 | vb2q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 217 | vb2q->io_modes = VB2_MMAP | VB2_READ | VB2_USERPTR; 218 | vb2q->drv_priv = dev; 219 | vb2q->buf_struct_size = sizeof(struct gvusb2_vb); 220 | vb2q->ops = &gvusb2_vb2_ops; 221 | vb2q->mem_ops = &vb2_vmalloc_memops; 222 | vb2q->lock = &dev->vb2q_lock; 223 | /* what is this for? */ 224 | vb2q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 225 | 226 | INIT_LIST_HEAD(&dev->buf_list); 227 | 228 | ret = vb2_queue_init(vb2q); 229 | if (ret < 0) 230 | return ret; 231 | 232 | return 0; 233 | } 234 | 235 | /***************************************************************************** 236 | * V4L2 Control Functions 237 | ****************************************************************************/ 238 | 239 | static int gvusb2_s_ctrl(struct v4l2_ctrl *ctrl) 240 | { 241 | struct gvusb2_vid *dev = container_of(ctrl->handler, 242 | struct gvusb2_vid, ctrl_handler); 243 | 244 | switch (ctrl->id) { 245 | case V4L2_CID_BRIGHTNESS: 246 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x10, 247 | (ctrl->val + 0x80) & 0xff); 248 | break; 249 | case V4L2_CID_CONTRAST: 250 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x11, 251 | ctrl->val); 252 | break; 253 | case V4L2_CID_SATURATION: 254 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x13, 255 | ctrl->val); 256 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x14, 257 | ctrl->val); 258 | break; 259 | case V4L2_CID_HUE: 260 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x15, 261 | (ctrl->val + 0x80) & 0xff); 262 | break; 263 | case V4L2_CID_SHARPNESS: 264 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x12, 265 | (ctrl->val & 0x0f) | 0x50); 266 | break; 267 | case GVUSB2_CID_VERTICAL_START: 268 | gvusb2_write_reg(&dev->gv, 0x0112, ctrl->val); 269 | gvusb2_write_reg(&dev->gv, 0x0113, 0); 270 | gvusb2_write_reg(&dev->gv, 0x0116, ctrl->val + 0xf0); 271 | gvusb2_write_reg(&dev->gv, 0x0117, 0); 272 | break; 273 | case GVUSB2_CID_HORIZONTAL_START: 274 | gvusb2_write_reg(&dev->gv, 0x0110, ctrl->val); 275 | gvusb2_write_reg(&dev->gv, 0x0111, 0); 276 | gvusb2_write_reg(&dev->gv, 0x0114, ctrl->val + 0xa0); 277 | gvusb2_write_reg(&dev->gv, 0x0115, 0x05); 278 | break; 279 | } 280 | 281 | return 0; 282 | } 283 | 284 | static const struct v4l2_ctrl_ops gvusb2_ctrl_ops = { 285 | .s_ctrl = gvusb2_s_ctrl, 286 | }; 287 | 288 | static const struct v4l2_ctrl_config gvusb2_ctrl_vertical = { 289 | .ops = &gvusb2_ctrl_ops, 290 | .id = GVUSB2_CID_VERTICAL_START, 291 | .name = "Vertical Start", 292 | .type = V4L2_CTRL_TYPE_INTEGER, 293 | .flags = V4L2_CTRL_FLAG_SLIDER, 294 | .min = 1, 295 | .max = 4, 296 | .step = 1, 297 | .def = 2, 298 | }; 299 | 300 | static const struct v4l2_ctrl_config gvusb2_ctrl_horizontal = { 301 | .ops = &gvusb2_ctrl_ops, 302 | .id = GVUSB2_CID_HORIZONTAL_START, 303 | .name = "Horizontal Start", 304 | .type = V4L2_CTRL_TYPE_INTEGER, 305 | .flags = V4L2_CTRL_FLAG_SLIDER, 306 | .min = 0, 307 | .max = 8, 308 | .step = 4, 309 | .def = 4, 310 | }; 311 | 312 | /***************************************************************************** 313 | * Video4Linux2 functions 314 | ****************************************************************************/ 315 | 316 | static int gvusb2_vidioc_querycap(struct file *file, void *priv, 317 | struct v4l2_capability *cap) 318 | { 319 | struct gvusb2_vid *dev = video_drvdata(file); 320 | 321 | strscpy(cap->driver, "gvusb2", sizeof(cap->driver)); 322 | strscpy(cap->card, "gvusb2", sizeof(cap->card)); 323 | usb_make_path(dev->gv.udev, cap->bus_info, sizeof(cap->bus_info)); 324 | 325 | return 0; 326 | } 327 | 328 | static int gvusb2_vidioc_enum_input(struct file *file, void *priv, 329 | struct v4l2_input *i) 330 | { 331 | struct gvusb2_vid *dev = video_drvdata(file); 332 | 333 | switch (i->index) { 334 | case GVUSB2_INPUT_COMPOSITE: 335 | strncpy(i->name, "Composite", sizeof(i->name)); 336 | break; 337 | case GVUSB2_INPUT_SVIDEO: 338 | strncpy(i->name, "S-Video", sizeof(i->name)); 339 | break; 340 | default: 341 | return -EINVAL; 342 | } 343 | 344 | i->type = V4L2_INPUT_TYPE_CAMERA; 345 | i->capabilities = V4L2_IN_CAP_STD; 346 | i->std = dev->vdev.tvnorms; 347 | 348 | return 0; 349 | } 350 | 351 | static int gvusb2_vidioc_g_input(struct file *file, void *priv, unsigned int *i) 352 | { 353 | struct gvusb2_vid *dev = video_drvdata(file); 354 | 355 | *i = dev->input_num; 356 | 357 | return 0; 358 | } 359 | 360 | static int gvusb2_vidioc_s_input(struct file *file, void *priv, unsigned int i) 361 | { 362 | struct gvusb2_vid *dev = video_drvdata(file); 363 | u8 val; 364 | s32 reg; 365 | 366 | switch (i) { 367 | case GVUSB2_INPUT_COMPOSITE: 368 | /* set Composite and Mux 0 */ 369 | val = 0x00; 370 | break; 371 | case GVUSB2_INPUT_SVIDEO: 372 | /* set S-Video and Mux 1 */ 373 | val = 0x14; 374 | break; 375 | default: 376 | return -EINVAL; 377 | } 378 | 379 | reg = i2c_smbus_read_byte_data(&dev->i2c_client, 0x02); 380 | if (reg < 0) 381 | return reg; 382 | 383 | i2c_smbus_write_byte_data(&dev->i2c_client, 0x02, (reg & 0xc3) | val); 384 | if (reg < 0) 385 | return reg; 386 | 387 | dev->input_num = i; 388 | 389 | return 0; 390 | } 391 | 392 | static int gvusb2_vidioc_querystd(struct file *file, void *priv, 393 | v4l2_std_id *std) 394 | { 395 | struct gvusb2_vid *dev = video_drvdata(file); 396 | 397 | /* we can't querystd with the current tw9910 driver */ 398 | *std = dev->vdev.tvnorms; 399 | 400 | return 0; 401 | } 402 | 403 | static int gvusb2_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) 404 | { 405 | struct gvusb2_vid *dev = video_drvdata(file); 406 | 407 | *std = dev->standard; 408 | 409 | return 0; 410 | } 411 | 412 | static int gvusb2_vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) 413 | { 414 | struct gvusb2_vid *dev = video_drvdata(file); 415 | struct vb2_queue *vb2q = &dev->vb2q; 416 | 417 | if (std == dev->standard) 418 | return 0; 419 | 420 | if (vb2_is_busy(vb2q)) 421 | return -EBUSY; 422 | 423 | /* TODO: set standard based off of this */ 424 | dev->standard = std; 425 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, std); 426 | 427 | return 0; 428 | } 429 | 430 | static int gvusb2_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 431 | struct v4l2_fmtdesc *f) 432 | { 433 | if (f->index != 0) 434 | return -EINVAL; 435 | 436 | f->pixelformat = V4L2_PIX_FMT_UYVY; 437 | 438 | return 0; 439 | } 440 | 441 | static int gvusb2_vidioc_g_fmt_vid_cap(struct file *file, void *priv, 442 | struct v4l2_format *f) 443 | { 444 | struct gvusb2_vid *dev = video_drvdata(file); 445 | int width, height; 446 | 447 | get_resolution(dev, &width, &height); 448 | f->fmt.pix.width = width; 449 | f->fmt.pix.height = height; 450 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; 451 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 452 | f->fmt.pix.bytesperline = width * 2; 453 | f->fmt.pix.sizeimage = height * width * 2; 454 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 455 | 456 | return 0; 457 | } 458 | 459 | static int gvusb2_vidioc_s_fmt_vid_cap(struct file *file, void *priv, 460 | struct v4l2_format *f) 461 | { 462 | struct gvusb2_vid *dev = video_drvdata(file); 463 | struct vb2_queue *vb2q = &dev->vb2q; 464 | int width, height; 465 | 466 | if (vb2_is_busy(vb2q)) 467 | return -EBUSY; 468 | 469 | get_resolution(dev, &width, &height); 470 | f->fmt.pix.width = width; 471 | f->fmt.pix.height = height; 472 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; 473 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 474 | f->fmt.pix.bytesperline = width * 2; 475 | f->fmt.pix.sizeimage = height * width * 2; 476 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 477 | 478 | return 0; 479 | } 480 | 481 | static int gvusb2_vidioc_try_fmt_vid_cap(struct file *file, void *priv, 482 | struct v4l2_format *f) 483 | { 484 | struct gvusb2_vid *dev = video_drvdata(file); 485 | int width, height; 486 | 487 | get_resolution(dev, &width, &height); 488 | f->fmt.pix.width = width; 489 | f->fmt.pix.height = height; 490 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; 491 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 492 | f->fmt.pix.bytesperline = width * 2; 493 | f->fmt.pix.sizeimage = height * width * 2; 494 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 495 | 496 | return 0; 497 | } 498 | 499 | static const struct v4l2_ioctl_ops gvusb2_v4l2_ioctl_ops = { 500 | .vidioc_querycap = gvusb2_vidioc_querycap, 501 | .vidioc_enum_input = gvusb2_vidioc_enum_input, 502 | .vidioc_g_input = gvusb2_vidioc_g_input, 503 | .vidioc_s_input = gvusb2_vidioc_s_input, 504 | .vidioc_querystd = gvusb2_vidioc_querystd, 505 | .vidioc_g_std = gvusb2_vidioc_g_std, 506 | .vidioc_s_std = gvusb2_vidioc_s_std, 507 | .vidioc_enum_fmt_vid_cap = gvusb2_vidioc_enum_fmt_vid_cap, 508 | .vidioc_g_fmt_vid_cap = gvusb2_vidioc_g_fmt_vid_cap, 509 | .vidioc_s_fmt_vid_cap = gvusb2_vidioc_s_fmt_vid_cap, 510 | .vidioc_try_fmt_vid_cap = gvusb2_vidioc_try_fmt_vid_cap, 511 | 512 | .vidioc_reqbufs = vb2_ioctl_reqbufs, 513 | .vidioc_querybuf = vb2_ioctl_querybuf, 514 | .vidioc_qbuf = vb2_ioctl_qbuf, 515 | .vidioc_dqbuf = vb2_ioctl_dqbuf, 516 | .vidioc_create_bufs = vb2_ioctl_create_bufs, 517 | .vidioc_streamon = vb2_ioctl_streamon, 518 | .vidioc_streamoff = vb2_ioctl_streamoff, 519 | .vidioc_expbuf = vb2_ioctl_expbuf, 520 | 521 | .vidioc_log_status = v4l2_ctrl_log_status, 522 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 523 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 524 | }; 525 | 526 | static struct tw9910_video_info gvusb2_tw9910_video_info = { 527 | .buswidth = 8, 528 | .mpout = TW9910_MPO_FIELD, 529 | }; 530 | 531 | static struct i2c_board_info gvusb2_tw9910_i2c_board_info = { 532 | .type = "tw9910", 533 | .addr = 0x44, 534 | .platform_data = &gvusb2_tw9910_video_info, 535 | }; 536 | 537 | int gvusb2_v4l2_register(struct gvusb2_vid *dev) 538 | { 539 | int i; 540 | int ret; 541 | 542 | static const struct i2c_regval phase6[] = { 543 | {0x06, 0x00}, 544 | {0x03, 0xa2}, 545 | {0x05, 0x01}, 546 | //{0x08, 0x12}, 547 | //{0x09, 0xf4}, 548 | {0x19, 0xde}, 549 | {0x1a, 0x0f}, 550 | {0x1b, 0x00}, 551 | //{0x1c, 0x0f}, 552 | //{0x28, 0x0e}, 553 | //{0x2e, 0xa5}, 554 | //{0x2f, 0x06}, 555 | //{0x6b, 0x26}, 556 | //{0x6c, 0x36}, 557 | //{0x6d, 0xf0}, 558 | {0x6e, 0x28}, 559 | {0x06, 0x80}, 560 | {0xff, 0xff} 561 | }; 562 | 563 | /* init our v4l2 lock */ 564 | mutex_init(&dev->v4l2_lock); 565 | 566 | /* make our ctrl handler */ 567 | ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, 5); 568 | if (ret < 0) 569 | return ret; 570 | 571 | dev->v4l2_dev.release = gvusb2_release; 572 | dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler; 573 | 574 | /* register controls */ 575 | v4l2_ctrl_new_std(&dev->ctrl_handler, &gvusb2_ctrl_ops, 576 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 577 | v4l2_ctrl_new_std(&dev->ctrl_handler, &gvusb2_ctrl_ops, 578 | V4L2_CID_CONTRAST, 0, 255, 1, 128); 579 | v4l2_ctrl_new_std(&dev->ctrl_handler, &gvusb2_ctrl_ops, 580 | V4L2_CID_SATURATION, 0, 255, 1, 128); 581 | v4l2_ctrl_new_std(&dev->ctrl_handler, &gvusb2_ctrl_ops, 582 | V4L2_CID_HUE, 0, 255, 1, 128); 583 | v4l2_ctrl_new_std(&dev->ctrl_handler, &gvusb2_ctrl_ops, 584 | V4L2_CID_SHARPNESS, 0, 15, 1, 0); 585 | v4l2_ctrl_new_custom(&dev->ctrl_handler, &gvusb2_ctrl_vertical, NULL); 586 | v4l2_ctrl_new_custom(&dev->ctrl_handler, &gvusb2_ctrl_horizontal, NULL); 587 | 588 | if (dev->ctrl_handler.error) { 589 | ret = dev->ctrl_handler.error; 590 | goto free_ctrl_handler; 591 | } 592 | 593 | /* initialize control to default values */ 594 | v4l2_ctrl_handler_setup(&dev->ctrl_handler); 595 | 596 | ret = v4l2_device_register(&dev->intf->dev, &dev->v4l2_dev); 597 | if (ret < 0) 598 | goto free_ctrl_handler; 599 | 600 | /* load tw9910 driver */ 601 | dev->sd_tw9910 = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->adap, 602 | &gvusb2_tw9910_i2c_board_info, 0); 603 | 604 | /* init tw9910 */ 605 | for (i = 0; phase6[i].reg != 0xff; i++) 606 | i2c_smbus_write_byte_data(&dev->i2c_client, 607 | phase6[i].reg, phase6[i].val); 608 | 609 | /* set STK1150 to always double word */ 610 | /* not quite sure the importance */ 611 | gvusb2_set_reg_mask(&dev->gv, 0x05f0, 0x08, 0x08); 612 | 613 | return 0; 614 | 615 | free_ctrl_handler: 616 | v4l2_ctrl_handler_free(&dev->ctrl_handler); 617 | 618 | return ret; 619 | } 620 | 621 | void gvusb2_v4l2_unregister(struct gvusb2_vid *dev) 622 | { 623 | v4l2_device_unregister(&dev->v4l2_dev); 624 | } 625 | 626 | static const struct v4l2_file_operations gvusb2_v4l2_fops = { 627 | .owner = THIS_MODULE, 628 | .open = v4l2_fh_open, 629 | .release = vb2_fop_release, 630 | .read = vb2_fop_read, 631 | .poll = vb2_fop_poll, 632 | .mmap = vb2_fop_mmap, 633 | .unlocked_ioctl = video_ioctl2, 634 | }; 635 | 636 | static const struct video_device gvusb2_video_device_template = { 637 | .name = "gvusb2", 638 | .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | 639 | V4L2_CAP_READWRITE, 640 | .tvnorms = V4L2_STD_525_60 | V4L2_STD_625_50, 641 | .vfl_dir = VFL_DIR_RX, 642 | .fops = &gvusb2_v4l2_fops, 643 | .ioctl_ops = &gvusb2_v4l2_ioctl_ops, 644 | .release = video_device_release_empty, 645 | }; 646 | 647 | int gvusb2_video_register(struct gvusb2_vid *dev) 648 | { 649 | int ret; 650 | 651 | /* init vdev data */ 652 | dev->vdev = gvusb2_video_device_template; 653 | 654 | dev->vdev.v4l2_dev = &dev->v4l2_dev; 655 | dev->vdev.queue = &dev->vb2q; 656 | dev->vdev.lock = &dev->v4l2_lock; 657 | 658 | /* set standard for device */ 659 | dev->standard = V4L2_STD_NTSC_M; 660 | 661 | /* set standard for sub-devices */ 662 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, 663 | dev->standard); 664 | 665 | video_set_drvdata(&dev->vdev, dev); 666 | ret = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1); 667 | if (ret < 0) 668 | return ret; 669 | 670 | return 0; 671 | } 672 | --------------------------------------------------------------------------------