as102_usb_drv.c (11635B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Abilis Systems Single DVB-T Receiver 4 * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> 5 * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> 6 */ 7#include <linux/kernel.h> 8#include <linux/errno.h> 9#include <linux/slab.h> 10#include <linux/mm.h> 11#include <linux/usb.h> 12 13#include "as102_drv.h" 14#include "as102_usb_drv.h" 15#include "as102_fw.h" 16 17static void as102_usb_disconnect(struct usb_interface *interface); 18static int as102_usb_probe(struct usb_interface *interface, 19 const struct usb_device_id *id); 20 21static int as102_usb_start_stream(struct as102_dev_t *dev); 22static void as102_usb_stop_stream(struct as102_dev_t *dev); 23 24static int as102_open(struct inode *inode, struct file *file); 25static int as102_release(struct inode *inode, struct file *file); 26 27static const struct usb_device_id as102_usb_id_table[] = { 28 { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, 29 { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, 30 { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, 31 { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) }, 32 { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) }, 33 { } /* Terminating entry */ 34}; 35 36/* Note that this table must always have the same number of entries as the 37 as102_usb_id_table struct */ 38static const char * const as102_device_names[] = { 39 AS102_REFERENCE_DESIGN, 40 AS102_PCTV_74E, 41 AS102_ELGATO_EYETV_DTT_NAME, 42 AS102_NBOX_DVBT_DONGLE_NAME, 43 AS102_SKY_IT_DIGITAL_KEY_NAME, 44 NULL /* Terminating entry */ 45}; 46 47/* eLNA configuration: devices built on the reference design work best 48 with 0xA0, while custom designs seem to require 0xC0 */ 49static uint8_t const as102_elna_cfg[] = { 50 0xA0, 51 0xC0, 52 0xC0, 53 0xA0, 54 0xA0, 55 0x00 /* Terminating entry */ 56}; 57 58struct usb_driver as102_usb_driver = { 59 .name = DRIVER_FULL_NAME, 60 .probe = as102_usb_probe, 61 .disconnect = as102_usb_disconnect, 62 .id_table = as102_usb_id_table 63}; 64 65static const struct file_operations as102_dev_fops = { 66 .owner = THIS_MODULE, 67 .open = as102_open, 68 .release = as102_release, 69}; 70 71static struct usb_class_driver as102_usb_class_driver = { 72 .name = "aton2-%d", 73 .fops = &as102_dev_fops, 74 .minor_base = AS102_DEVICE_MAJOR, 75}; 76 77static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, 78 unsigned char *send_buf, int send_buf_len, 79 unsigned char *recv_buf, int recv_buf_len) 80{ 81 int ret = 0; 82 83 if (send_buf != NULL) { 84 ret = usb_control_msg(bus_adap->usb_dev, 85 usb_sndctrlpipe(bus_adap->usb_dev, 0), 86 AS102_USB_DEVICE_TX_CTRL_CMD, 87 USB_DIR_OUT | USB_TYPE_VENDOR | 88 USB_RECIP_DEVICE, 89 bus_adap->cmd_xid, /* value */ 90 0, /* index */ 91 send_buf, send_buf_len, 92 USB_CTRL_SET_TIMEOUT /* 200 */); 93 if (ret < 0) { 94 dev_dbg(&bus_adap->usb_dev->dev, 95 "usb_control_msg(send) failed, err %i\n", ret); 96 return ret; 97 } 98 99 if (ret != send_buf_len) { 100 dev_dbg(&bus_adap->usb_dev->dev, 101 "only wrote %d of %d bytes\n", ret, send_buf_len); 102 return -1; 103 } 104 } 105 106 if (recv_buf != NULL) { 107#ifdef TRACE 108 dev_dbg(bus_adap->usb_dev->dev, 109 "want to read: %d bytes\n", recv_buf_len); 110#endif 111 ret = usb_control_msg(bus_adap->usb_dev, 112 usb_rcvctrlpipe(bus_adap->usb_dev, 0), 113 AS102_USB_DEVICE_RX_CTRL_CMD, 114 USB_DIR_IN | USB_TYPE_VENDOR | 115 USB_RECIP_DEVICE, 116 bus_adap->cmd_xid, /* value */ 117 0, /* index */ 118 recv_buf, recv_buf_len, 119 USB_CTRL_GET_TIMEOUT /* 200 */); 120 if (ret < 0) { 121 dev_dbg(&bus_adap->usb_dev->dev, 122 "usb_control_msg(recv) failed, err %i\n", ret); 123 return ret; 124 } 125#ifdef TRACE 126 dev_dbg(bus_adap->usb_dev->dev, 127 "read %d bytes\n", recv_buf_len); 128#endif 129 } 130 131 return ret; 132} 133 134static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, 135 unsigned char *send_buf, 136 int send_buf_len, 137 int swap32) 138{ 139 int ret, actual_len; 140 141 ret = usb_bulk_msg(bus_adap->usb_dev, 142 usb_sndbulkpipe(bus_adap->usb_dev, 1), 143 send_buf, send_buf_len, &actual_len, 200); 144 if (ret) { 145 dev_dbg(&bus_adap->usb_dev->dev, 146 "usb_bulk_msg(send) failed, err %i\n", ret); 147 return ret; 148 } 149 150 if (actual_len != send_buf_len) { 151 dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n", 152 actual_len, send_buf_len); 153 return -1; 154 } 155 return actual_len; 156} 157 158static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, 159 unsigned char *recv_buf, int recv_buf_len) 160{ 161 int ret, actual_len; 162 163 if (recv_buf == NULL) 164 return -EINVAL; 165 166 ret = usb_bulk_msg(bus_adap->usb_dev, 167 usb_rcvbulkpipe(bus_adap->usb_dev, 2), 168 recv_buf, recv_buf_len, &actual_len, 200); 169 if (ret) { 170 dev_dbg(&bus_adap->usb_dev->dev, 171 "usb_bulk_msg(recv) failed, err %i\n", ret); 172 return ret; 173 } 174 175 if (actual_len != recv_buf_len) { 176 dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n", 177 actual_len, recv_buf_len); 178 return -1; 179 } 180 return actual_len; 181} 182 183static const struct as102_priv_ops_t as102_priv_ops = { 184 .upload_fw_pkt = as102_send_ep1, 185 .xfer_cmd = as102_usb_xfer_cmd, 186 .as102_read_ep2 = as102_read_ep2, 187 .start_stream = as102_usb_start_stream, 188 .stop_stream = as102_usb_stop_stream, 189}; 190 191static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) 192{ 193 int err; 194 195 usb_fill_bulk_urb(urb, 196 dev->bus_adap.usb_dev, 197 usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2), 198 urb->transfer_buffer, 199 AS102_USB_BUF_SIZE, 200 as102_urb_stream_irq, 201 dev); 202 203 err = usb_submit_urb(urb, GFP_ATOMIC); 204 if (err) 205 dev_dbg(&urb->dev->dev, 206 "%s: usb_submit_urb failed\n", __func__); 207 208 return err; 209} 210 211void as102_urb_stream_irq(struct urb *urb) 212{ 213 struct as102_dev_t *as102_dev = urb->context; 214 215 if (urb->actual_length > 0) { 216 dvb_dmx_swfilter(&as102_dev->dvb_dmx, 217 urb->transfer_buffer, 218 urb->actual_length); 219 } else { 220 if (urb->actual_length == 0) 221 memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE); 222 } 223 224 /* is not stopped, re-submit urb */ 225 if (as102_dev->streaming) 226 as102_submit_urb_stream(as102_dev, urb); 227} 228 229static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) 230{ 231 int i; 232 233 for (i = 0; i < MAX_STREAM_URB; i++) 234 usb_free_urb(dev->stream_urb[i]); 235 236 usb_free_coherent(dev->bus_adap.usb_dev, 237 MAX_STREAM_URB * AS102_USB_BUF_SIZE, 238 dev->stream, 239 dev->dma_addr); 240} 241 242static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) 243{ 244 int i; 245 246 dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev, 247 MAX_STREAM_URB * AS102_USB_BUF_SIZE, 248 GFP_KERNEL, 249 &dev->dma_addr); 250 if (!dev->stream) { 251 dev_dbg(&dev->bus_adap.usb_dev->dev, 252 "%s: usb_buffer_alloc failed\n", __func__); 253 return -ENOMEM; 254 } 255 256 memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE); 257 258 /* init urb buffers */ 259 for (i = 0; i < MAX_STREAM_URB; i++) { 260 struct urb *urb; 261 262 urb = usb_alloc_urb(0, GFP_ATOMIC); 263 if (urb == NULL) { 264 as102_free_usb_stream_buffer(dev); 265 return -ENOMEM; 266 } 267 268 urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE); 269 urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE); 270 urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; 271 urb->transfer_buffer_length = AS102_USB_BUF_SIZE; 272 273 dev->stream_urb[i] = urb; 274 } 275 return 0; 276} 277 278static void as102_usb_stop_stream(struct as102_dev_t *dev) 279{ 280 int i; 281 282 for (i = 0; i < MAX_STREAM_URB; i++) 283 usb_kill_urb(dev->stream_urb[i]); 284} 285 286static int as102_usb_start_stream(struct as102_dev_t *dev) 287{ 288 int i, ret = 0; 289 290 for (i = 0; i < MAX_STREAM_URB; i++) { 291 ret = as102_submit_urb_stream(dev, dev->stream_urb[i]); 292 if (ret) { 293 as102_usb_stop_stream(dev); 294 return ret; 295 } 296 } 297 298 return 0; 299} 300 301static void as102_usb_release(struct kref *kref) 302{ 303 struct as102_dev_t *as102_dev; 304 305 as102_dev = container_of(kref, struct as102_dev_t, kref); 306 if (as102_dev != NULL) { 307 usb_put_dev(as102_dev->bus_adap.usb_dev); 308 kfree(as102_dev); 309 } 310} 311 312static void as102_usb_disconnect(struct usb_interface *intf) 313{ 314 struct as102_dev_t *as102_dev; 315 316 /* extract as102_dev_t from usb_device private data */ 317 as102_dev = usb_get_intfdata(intf); 318 319 /* unregister dvb layer */ 320 as102_dvb_unregister(as102_dev); 321 322 /* free usb buffers */ 323 as102_free_usb_stream_buffer(as102_dev); 324 325 usb_set_intfdata(intf, NULL); 326 327 /* usb unregister device */ 328 usb_deregister_dev(intf, &as102_usb_class_driver); 329 330 /* decrement usage counter */ 331 kref_put(&as102_dev->kref, as102_usb_release); 332 333 pr_info("%s: device has been disconnected\n", DRIVER_NAME); 334} 335 336static int as102_usb_probe(struct usb_interface *intf, 337 const struct usb_device_id *id) 338{ 339 int ret; 340 struct as102_dev_t *as102_dev; 341 int i; 342 343 /* This should never actually happen */ 344 if (ARRAY_SIZE(as102_usb_id_table) != 345 (sizeof(as102_device_names) / sizeof(const char *))) { 346 pr_err("Device names table invalid size"); 347 return -EINVAL; 348 } 349 350 as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); 351 if (as102_dev == NULL) 352 return -ENOMEM; 353 354 /* Assign the user-friendly device name */ 355 for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) { 356 if (id == &as102_usb_id_table[i]) { 357 as102_dev->name = as102_device_names[i]; 358 as102_dev->elna_cfg = as102_elna_cfg[i]; 359 } 360 } 361 362 if (as102_dev->name == NULL) 363 as102_dev->name = "Unknown AS102 device"; 364 365 /* set private callback functions */ 366 as102_dev->bus_adap.ops = &as102_priv_ops; 367 368 /* init cmd token for usb bus */ 369 as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c; 370 as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r; 371 372 /* init kernel device reference */ 373 kref_init(&as102_dev->kref); 374 375 /* store as102 device to usb_device private data */ 376 usb_set_intfdata(intf, (void *) as102_dev); 377 378 /* store in as102 device the usb_device pointer */ 379 as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf)); 380 381 /* we can register the device now, as it is ready */ 382 ret = usb_register_dev(intf, &as102_usb_class_driver); 383 if (ret < 0) { 384 /* something prevented us from registering this driver */ 385 dev_err(&intf->dev, 386 "%s: usb_register_dev() failed (errno = %d)\n", 387 __func__, ret); 388 goto failed; 389 } 390 391 pr_info("%s: device has been detected\n", DRIVER_NAME); 392 393 /* request buffer allocation for streaming */ 394 ret = as102_alloc_usb_stream_buffer(as102_dev); 395 if (ret != 0) 396 goto failed_stream; 397 398 /* register dvb layer */ 399 ret = as102_dvb_register(as102_dev); 400 if (ret != 0) 401 goto failed_dvb; 402 403 return ret; 404 405failed_dvb: 406 as102_free_usb_stream_buffer(as102_dev); 407failed_stream: 408 usb_deregister_dev(intf, &as102_usb_class_driver); 409failed: 410 usb_put_dev(as102_dev->bus_adap.usb_dev); 411 usb_set_intfdata(intf, NULL); 412 kfree(as102_dev); 413 return ret; 414} 415 416static int as102_open(struct inode *inode, struct file *file) 417{ 418 int ret = 0, minor = 0; 419 struct usb_interface *intf = NULL; 420 struct as102_dev_t *dev = NULL; 421 422 /* read minor from inode */ 423 minor = iminor(inode); 424 425 /* fetch device from usb interface */ 426 intf = usb_find_interface(&as102_usb_driver, minor); 427 if (intf == NULL) { 428 pr_err("%s: can't find device for minor %d\n", 429 __func__, minor); 430 ret = -ENODEV; 431 goto exit; 432 } 433 434 /* get our device */ 435 dev = usb_get_intfdata(intf); 436 if (dev == NULL) { 437 ret = -EFAULT; 438 goto exit; 439 } 440 441 /* save our device object in the file's private structure */ 442 file->private_data = dev; 443 444 /* increment our usage count for the device */ 445 kref_get(&dev->kref); 446 447exit: 448 return ret; 449} 450 451static int as102_release(struct inode *inode, struct file *file) 452{ 453 struct as102_dev_t *dev = NULL; 454 455 dev = file->private_data; 456 if (dev != NULL) { 457 /* decrement the count on our device */ 458 kref_put(&dev->kref, as102_usb_release); 459 } 460 461 return 0; 462} 463 464MODULE_DEVICE_TABLE(usb, as102_usb_id_table);