162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Abilis Systems Single DVB-T Receiver 462306a36Sopenharmony_ci * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> 562306a36Sopenharmony_ci * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/mm.h> 1162306a36Sopenharmony_ci#include <linux/usb.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "as102_drv.h" 1462306a36Sopenharmony_ci#include "as102_usb_drv.h" 1562306a36Sopenharmony_ci#include "as102_fw.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic void as102_usb_disconnect(struct usb_interface *interface); 1862306a36Sopenharmony_cistatic int as102_usb_probe(struct usb_interface *interface, 1962306a36Sopenharmony_ci const struct usb_device_id *id); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int as102_usb_start_stream(struct as102_dev_t *dev); 2262306a36Sopenharmony_cistatic void as102_usb_stop_stream(struct as102_dev_t *dev); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int as102_open(struct inode *inode, struct file *file); 2562306a36Sopenharmony_cistatic int as102_release(struct inode *inode, struct file *file); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const struct usb_device_id as102_usb_id_table[] = { 2862306a36Sopenharmony_ci { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, 2962306a36Sopenharmony_ci { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, 3062306a36Sopenharmony_ci { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, 3162306a36Sopenharmony_ci { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) }, 3262306a36Sopenharmony_ci { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) }, 3362306a36Sopenharmony_ci { } /* Terminating entry */ 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* Note that this table must always have the same number of entries as the 3762306a36Sopenharmony_ci as102_usb_id_table struct */ 3862306a36Sopenharmony_cistatic const char * const as102_device_names[] = { 3962306a36Sopenharmony_ci AS102_REFERENCE_DESIGN, 4062306a36Sopenharmony_ci AS102_PCTV_74E, 4162306a36Sopenharmony_ci AS102_ELGATO_EYETV_DTT_NAME, 4262306a36Sopenharmony_ci AS102_NBOX_DVBT_DONGLE_NAME, 4362306a36Sopenharmony_ci AS102_SKY_IT_DIGITAL_KEY_NAME, 4462306a36Sopenharmony_ci NULL /* Terminating entry */ 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* eLNA configuration: devices built on the reference design work best 4862306a36Sopenharmony_ci with 0xA0, while custom designs seem to require 0xC0 */ 4962306a36Sopenharmony_cistatic uint8_t const as102_elna_cfg[] = { 5062306a36Sopenharmony_ci 0xA0, 5162306a36Sopenharmony_ci 0xC0, 5262306a36Sopenharmony_ci 0xC0, 5362306a36Sopenharmony_ci 0xA0, 5462306a36Sopenharmony_ci 0xA0, 5562306a36Sopenharmony_ci 0x00 /* Terminating entry */ 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistruct usb_driver as102_usb_driver = { 5962306a36Sopenharmony_ci .name = DRIVER_FULL_NAME, 6062306a36Sopenharmony_ci .probe = as102_usb_probe, 6162306a36Sopenharmony_ci .disconnect = as102_usb_disconnect, 6262306a36Sopenharmony_ci .id_table = as102_usb_id_table 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const struct file_operations as102_dev_fops = { 6662306a36Sopenharmony_ci .owner = THIS_MODULE, 6762306a36Sopenharmony_ci .open = as102_open, 6862306a36Sopenharmony_ci .release = as102_release, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic struct usb_class_driver as102_usb_class_driver = { 7262306a36Sopenharmony_ci .name = "aton2-%d", 7362306a36Sopenharmony_ci .fops = &as102_dev_fops, 7462306a36Sopenharmony_ci .minor_base = AS102_DEVICE_MAJOR, 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, 7862306a36Sopenharmony_ci unsigned char *send_buf, int send_buf_len, 7962306a36Sopenharmony_ci unsigned char *recv_buf, int recv_buf_len) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci int ret = 0; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (send_buf != NULL) { 8462306a36Sopenharmony_ci ret = usb_control_msg(bus_adap->usb_dev, 8562306a36Sopenharmony_ci usb_sndctrlpipe(bus_adap->usb_dev, 0), 8662306a36Sopenharmony_ci AS102_USB_DEVICE_TX_CTRL_CMD, 8762306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | 8862306a36Sopenharmony_ci USB_RECIP_DEVICE, 8962306a36Sopenharmony_ci bus_adap->cmd_xid, /* value */ 9062306a36Sopenharmony_ci 0, /* index */ 9162306a36Sopenharmony_ci send_buf, send_buf_len, 9262306a36Sopenharmony_ci USB_CTRL_SET_TIMEOUT /* 200 */); 9362306a36Sopenharmony_ci if (ret < 0) { 9462306a36Sopenharmony_ci dev_dbg(&bus_adap->usb_dev->dev, 9562306a36Sopenharmony_ci "usb_control_msg(send) failed, err %i\n", ret); 9662306a36Sopenharmony_ci return ret; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (ret != send_buf_len) { 10062306a36Sopenharmony_ci dev_dbg(&bus_adap->usb_dev->dev, 10162306a36Sopenharmony_ci "only wrote %d of %d bytes\n", ret, send_buf_len); 10262306a36Sopenharmony_ci return -1; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (recv_buf != NULL) { 10762306a36Sopenharmony_ci#ifdef TRACE 10862306a36Sopenharmony_ci dev_dbg(bus_adap->usb_dev->dev, 10962306a36Sopenharmony_ci "want to read: %d bytes\n", recv_buf_len); 11062306a36Sopenharmony_ci#endif 11162306a36Sopenharmony_ci ret = usb_control_msg(bus_adap->usb_dev, 11262306a36Sopenharmony_ci usb_rcvctrlpipe(bus_adap->usb_dev, 0), 11362306a36Sopenharmony_ci AS102_USB_DEVICE_RX_CTRL_CMD, 11462306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | 11562306a36Sopenharmony_ci USB_RECIP_DEVICE, 11662306a36Sopenharmony_ci bus_adap->cmd_xid, /* value */ 11762306a36Sopenharmony_ci 0, /* index */ 11862306a36Sopenharmony_ci recv_buf, recv_buf_len, 11962306a36Sopenharmony_ci USB_CTRL_GET_TIMEOUT /* 200 */); 12062306a36Sopenharmony_ci if (ret < 0) { 12162306a36Sopenharmony_ci dev_dbg(&bus_adap->usb_dev->dev, 12262306a36Sopenharmony_ci "usb_control_msg(recv) failed, err %i\n", ret); 12362306a36Sopenharmony_ci return ret; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci#ifdef TRACE 12662306a36Sopenharmony_ci dev_dbg(bus_adap->usb_dev->dev, 12762306a36Sopenharmony_ci "read %d bytes\n", recv_buf_len); 12862306a36Sopenharmony_ci#endif 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return ret; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, 13562306a36Sopenharmony_ci unsigned char *send_buf, 13662306a36Sopenharmony_ci int send_buf_len, 13762306a36Sopenharmony_ci int swap32) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci int ret, actual_len; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci ret = usb_bulk_msg(bus_adap->usb_dev, 14262306a36Sopenharmony_ci usb_sndbulkpipe(bus_adap->usb_dev, 1), 14362306a36Sopenharmony_ci send_buf, send_buf_len, &actual_len, 200); 14462306a36Sopenharmony_ci if (ret) { 14562306a36Sopenharmony_ci dev_dbg(&bus_adap->usb_dev->dev, 14662306a36Sopenharmony_ci "usb_bulk_msg(send) failed, err %i\n", ret); 14762306a36Sopenharmony_ci return ret; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (actual_len != send_buf_len) { 15162306a36Sopenharmony_ci dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n", 15262306a36Sopenharmony_ci actual_len, send_buf_len); 15362306a36Sopenharmony_ci return -1; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci return actual_len; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, 15962306a36Sopenharmony_ci unsigned char *recv_buf, int recv_buf_len) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci int ret, actual_len; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (recv_buf == NULL) 16462306a36Sopenharmony_ci return -EINVAL; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci ret = usb_bulk_msg(bus_adap->usb_dev, 16762306a36Sopenharmony_ci usb_rcvbulkpipe(bus_adap->usb_dev, 2), 16862306a36Sopenharmony_ci recv_buf, recv_buf_len, &actual_len, 200); 16962306a36Sopenharmony_ci if (ret) { 17062306a36Sopenharmony_ci dev_dbg(&bus_adap->usb_dev->dev, 17162306a36Sopenharmony_ci "usb_bulk_msg(recv) failed, err %i\n", ret); 17262306a36Sopenharmony_ci return ret; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (actual_len != recv_buf_len) { 17662306a36Sopenharmony_ci dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n", 17762306a36Sopenharmony_ci actual_len, recv_buf_len); 17862306a36Sopenharmony_ci return -1; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci return actual_len; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic const struct as102_priv_ops_t as102_priv_ops = { 18462306a36Sopenharmony_ci .upload_fw_pkt = as102_send_ep1, 18562306a36Sopenharmony_ci .xfer_cmd = as102_usb_xfer_cmd, 18662306a36Sopenharmony_ci .as102_read_ep2 = as102_read_ep2, 18762306a36Sopenharmony_ci .start_stream = as102_usb_start_stream, 18862306a36Sopenharmony_ci .stop_stream = as102_usb_stop_stream, 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci int err; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci usb_fill_bulk_urb(urb, 19662306a36Sopenharmony_ci dev->bus_adap.usb_dev, 19762306a36Sopenharmony_ci usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2), 19862306a36Sopenharmony_ci urb->transfer_buffer, 19962306a36Sopenharmony_ci AS102_USB_BUF_SIZE, 20062306a36Sopenharmony_ci as102_urb_stream_irq, 20162306a36Sopenharmony_ci dev); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci err = usb_submit_urb(urb, GFP_ATOMIC); 20462306a36Sopenharmony_ci if (err) 20562306a36Sopenharmony_ci dev_dbg(&urb->dev->dev, 20662306a36Sopenharmony_ci "%s: usb_submit_urb failed\n", __func__); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return err; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_civoid as102_urb_stream_irq(struct urb *urb) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct as102_dev_t *as102_dev = urb->context; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (urb->actual_length > 0) { 21662306a36Sopenharmony_ci dvb_dmx_swfilter(&as102_dev->dvb_dmx, 21762306a36Sopenharmony_ci urb->transfer_buffer, 21862306a36Sopenharmony_ci urb->actual_length); 21962306a36Sopenharmony_ci } else { 22062306a36Sopenharmony_ci if (urb->actual_length == 0) 22162306a36Sopenharmony_ci memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* is not stopped, re-submit urb */ 22562306a36Sopenharmony_ci if (as102_dev->streaming) 22662306a36Sopenharmony_ci as102_submit_urb_stream(as102_dev, urb); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic void as102_free_usb_stream_buffer(struct as102_dev_t *dev) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci int i; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci for (i = 0; i < MAX_STREAM_URB; i++) 23462306a36Sopenharmony_ci usb_free_urb(dev->stream_urb[i]); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci usb_free_coherent(dev->bus_adap.usb_dev, 23762306a36Sopenharmony_ci MAX_STREAM_URB * AS102_USB_BUF_SIZE, 23862306a36Sopenharmony_ci dev->stream, 23962306a36Sopenharmony_ci dev->dma_addr); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci int i; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev, 24762306a36Sopenharmony_ci MAX_STREAM_URB * AS102_USB_BUF_SIZE, 24862306a36Sopenharmony_ci GFP_KERNEL, 24962306a36Sopenharmony_ci &dev->dma_addr); 25062306a36Sopenharmony_ci if (!dev->stream) { 25162306a36Sopenharmony_ci dev_dbg(&dev->bus_adap.usb_dev->dev, 25262306a36Sopenharmony_ci "%s: usb_buffer_alloc failed\n", __func__); 25362306a36Sopenharmony_ci return -ENOMEM; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* init urb buffers */ 25962306a36Sopenharmony_ci for (i = 0; i < MAX_STREAM_URB; i++) { 26062306a36Sopenharmony_ci struct urb *urb; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 26362306a36Sopenharmony_ci if (urb == NULL) { 26462306a36Sopenharmony_ci as102_free_usb_stream_buffer(dev); 26562306a36Sopenharmony_ci return -ENOMEM; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE); 26962306a36Sopenharmony_ci urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE); 27062306a36Sopenharmony_ci urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; 27162306a36Sopenharmony_ci urb->transfer_buffer_length = AS102_USB_BUF_SIZE; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci dev->stream_urb[i] = urb; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void as102_usb_stop_stream(struct as102_dev_t *dev) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int i; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci for (i = 0; i < MAX_STREAM_URB; i++) 28362306a36Sopenharmony_ci usb_kill_urb(dev->stream_urb[i]); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int as102_usb_start_stream(struct as102_dev_t *dev) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci int i, ret = 0; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci for (i = 0; i < MAX_STREAM_URB; i++) { 29162306a36Sopenharmony_ci ret = as102_submit_urb_stream(dev, dev->stream_urb[i]); 29262306a36Sopenharmony_ci if (ret) { 29362306a36Sopenharmony_ci as102_usb_stop_stream(dev); 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void as102_usb_release(struct kref *kref) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct as102_dev_t *as102_dev; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci as102_dev = container_of(kref, struct as102_dev_t, kref); 30662306a36Sopenharmony_ci usb_put_dev(as102_dev->bus_adap.usb_dev); 30762306a36Sopenharmony_ci kfree(as102_dev); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic void as102_usb_disconnect(struct usb_interface *intf) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct as102_dev_t *as102_dev; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* extract as102_dev_t from usb_device private data */ 31562306a36Sopenharmony_ci as102_dev = usb_get_intfdata(intf); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* unregister dvb layer */ 31862306a36Sopenharmony_ci as102_dvb_unregister(as102_dev); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* free usb buffers */ 32162306a36Sopenharmony_ci as102_free_usb_stream_buffer(as102_dev); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* usb unregister device */ 32662306a36Sopenharmony_ci usb_deregister_dev(intf, &as102_usb_class_driver); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* decrement usage counter */ 32962306a36Sopenharmony_ci kref_put(&as102_dev->kref, as102_usb_release); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci pr_info("%s: device has been disconnected\n", DRIVER_NAME); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int as102_usb_probe(struct usb_interface *intf, 33562306a36Sopenharmony_ci const struct usb_device_id *id) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci int ret; 33862306a36Sopenharmony_ci struct as102_dev_t *as102_dev; 33962306a36Sopenharmony_ci int i; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* This should never actually happen */ 34262306a36Sopenharmony_ci if (ARRAY_SIZE(as102_usb_id_table) != 34362306a36Sopenharmony_ci (sizeof(as102_device_names) / sizeof(const char *))) { 34462306a36Sopenharmony_ci pr_err("Device names table invalid size"); 34562306a36Sopenharmony_ci return -EINVAL; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); 34962306a36Sopenharmony_ci if (as102_dev == NULL) 35062306a36Sopenharmony_ci return -ENOMEM; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* Assign the user-friendly device name */ 35362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) { 35462306a36Sopenharmony_ci if (id == &as102_usb_id_table[i]) { 35562306a36Sopenharmony_ci as102_dev->name = as102_device_names[i]; 35662306a36Sopenharmony_ci as102_dev->elna_cfg = as102_elna_cfg[i]; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (as102_dev->name == NULL) 36162306a36Sopenharmony_ci as102_dev->name = "Unknown AS102 device"; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* set private callback functions */ 36462306a36Sopenharmony_ci as102_dev->bus_adap.ops = &as102_priv_ops; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* init cmd token for usb bus */ 36762306a36Sopenharmony_ci as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c; 36862306a36Sopenharmony_ci as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* init kernel device reference */ 37162306a36Sopenharmony_ci kref_init(&as102_dev->kref); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* store as102 device to usb_device private data */ 37462306a36Sopenharmony_ci usb_set_intfdata(intf, (void *) as102_dev); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* store in as102 device the usb_device pointer */ 37762306a36Sopenharmony_ci as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf)); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* we can register the device now, as it is ready */ 38062306a36Sopenharmony_ci ret = usb_register_dev(intf, &as102_usb_class_driver); 38162306a36Sopenharmony_ci if (ret < 0) { 38262306a36Sopenharmony_ci /* something prevented us from registering this driver */ 38362306a36Sopenharmony_ci dev_err(&intf->dev, 38462306a36Sopenharmony_ci "%s: usb_register_dev() failed (errno = %d)\n", 38562306a36Sopenharmony_ci __func__, ret); 38662306a36Sopenharmony_ci goto failed; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci pr_info("%s: device has been detected\n", DRIVER_NAME); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* request buffer allocation for streaming */ 39262306a36Sopenharmony_ci ret = as102_alloc_usb_stream_buffer(as102_dev); 39362306a36Sopenharmony_ci if (ret != 0) 39462306a36Sopenharmony_ci goto failed_stream; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* register dvb layer */ 39762306a36Sopenharmony_ci ret = as102_dvb_register(as102_dev); 39862306a36Sopenharmony_ci if (ret != 0) 39962306a36Sopenharmony_ci goto failed_dvb; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return ret; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cifailed_dvb: 40462306a36Sopenharmony_ci as102_free_usb_stream_buffer(as102_dev); 40562306a36Sopenharmony_cifailed_stream: 40662306a36Sopenharmony_ci usb_deregister_dev(intf, &as102_usb_class_driver); 40762306a36Sopenharmony_cifailed: 40862306a36Sopenharmony_ci usb_put_dev(as102_dev->bus_adap.usb_dev); 40962306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 41062306a36Sopenharmony_ci kfree(as102_dev); 41162306a36Sopenharmony_ci return ret; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic int as102_open(struct inode *inode, struct file *file) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci int ret = 0, minor = 0; 41762306a36Sopenharmony_ci struct usb_interface *intf = NULL; 41862306a36Sopenharmony_ci struct as102_dev_t *dev = NULL; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* read minor from inode */ 42162306a36Sopenharmony_ci minor = iminor(inode); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* fetch device from usb interface */ 42462306a36Sopenharmony_ci intf = usb_find_interface(&as102_usb_driver, minor); 42562306a36Sopenharmony_ci if (intf == NULL) { 42662306a36Sopenharmony_ci pr_err("%s: can't find device for minor %d\n", 42762306a36Sopenharmony_ci __func__, minor); 42862306a36Sopenharmony_ci ret = -ENODEV; 42962306a36Sopenharmony_ci goto exit; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* get our device */ 43362306a36Sopenharmony_ci dev = usb_get_intfdata(intf); 43462306a36Sopenharmony_ci if (dev == NULL) { 43562306a36Sopenharmony_ci ret = -EFAULT; 43662306a36Sopenharmony_ci goto exit; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* save our device object in the file's private structure */ 44062306a36Sopenharmony_ci file->private_data = dev; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* increment our usage count for the device */ 44362306a36Sopenharmony_ci kref_get(&dev->kref); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ciexit: 44662306a36Sopenharmony_ci return ret; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int as102_release(struct inode *inode, struct file *file) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct as102_dev_t *dev = NULL; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci dev = file->private_data; 45462306a36Sopenharmony_ci if (dev != NULL) { 45562306a36Sopenharmony_ci /* decrement the count on our device */ 45662306a36Sopenharmony_ci kref_put(&dev->kref, as102_usb_release); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, as102_usb_id_table); 463