1/* 2 * Driver for the NXP SAA7164 PCIe bridge 3 * 4 * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22#include "saa7164.h" 23 24static struct saa7164_tvnorm saa7164_tvnorms[] = { 25 { 26 .name = "NTSC-M", 27 .id = V4L2_STD_NTSC_M, 28 }, { 29 .name = "NTSC-JP", 30 .id = V4L2_STD_NTSC_M_JP, 31 } 32}; 33 34static const u32 saa7164_v4l2_ctrls[] = { 35 0 36}; 37 38/* Take the encoder configuration from the port struct and 39 * flush it to the hardware. 40 */ 41static void saa7164_vbi_configure(struct saa7164_port *port) 42{ 43 struct saa7164_dev *dev = port->dev; 44 dprintk(DBGLVL_VBI, "%s()\n", __func__); 45 46 port->vbi_params.width = port->width; 47 port->vbi_params.height = port->height; 48 port->vbi_params.is_50hz = 49 (port->encodernorm.id & V4L2_STD_625_50) != 0; 50 51 /* Set up the DIF (enable it) for analog mode by default */ 52 saa7164_api_initialize_dif(port); 53 54 /* Configure the correct video standard */ 55#if 0 56 saa7164_api_configure_dif(port, port->encodernorm.id); 57#endif 58 59#if 0 60 /* Ensure the audio decoder is correct configured */ 61 saa7164_api_set_audio_std(port); 62#endif 63 dprintk(DBGLVL_VBI, "%s() ends\n", __func__); 64} 65 66static int saa7164_vbi_buffers_dealloc(struct saa7164_port *port) 67{ 68 struct list_head *c, *n, *p, *q, *l, *v; 69 struct saa7164_dev *dev = port->dev; 70 struct saa7164_buffer *buf; 71 struct saa7164_user_buffer *ubuf; 72 73 /* Remove any allocated buffers */ 74 mutex_lock(&port->dmaqueue_lock); 75 76 dprintk(DBGLVL_VBI, "%s(port=%d) dmaqueue\n", __func__, port->nr); 77 list_for_each_safe(c, n, &port->dmaqueue.list) { 78 buf = list_entry(c, struct saa7164_buffer, list); 79 list_del(c); 80 saa7164_buffer_dealloc(buf); 81 } 82 83 dprintk(DBGLVL_VBI, "%s(port=%d) used\n", __func__, port->nr); 84 list_for_each_safe(p, q, &port->list_buf_used.list) { 85 ubuf = list_entry(p, struct saa7164_user_buffer, list); 86 list_del(p); 87 saa7164_buffer_dealloc_user(ubuf); 88 } 89 90 dprintk(DBGLVL_VBI, "%s(port=%d) free\n", __func__, port->nr); 91 list_for_each_safe(l, v, &port->list_buf_free.list) { 92 ubuf = list_entry(l, struct saa7164_user_buffer, list); 93 list_del(l); 94 saa7164_buffer_dealloc_user(ubuf); 95 } 96 97 mutex_unlock(&port->dmaqueue_lock); 98 dprintk(DBGLVL_VBI, "%s(port=%d) done\n", __func__, port->nr); 99 100 return 0; 101} 102 103/* Dynamic buffer switch at vbi start time */ 104static int saa7164_vbi_buffers_alloc(struct saa7164_port *port) 105{ 106 struct saa7164_dev *dev = port->dev; 107 struct saa7164_buffer *buf; 108 struct saa7164_user_buffer *ubuf; 109 struct tmHWStreamParameters *params = &port->hw_streamingparams; 110 int result = -ENODEV, i; 111 int len = 0; 112 113 dprintk(DBGLVL_VBI, "%s()\n", __func__); 114 115 /* TODO: NTSC SPECIFIC */ 116 /* Init and establish defaults */ 117 params->samplesperline = 1440; 118 params->numberoflines = 12; 119 params->numberoflines = 18; 120 params->pitch = 1600; 121 params->pitch = 1440; 122 params->numpagetables = 2 + 123 ((params->numberoflines * params->pitch) / PAGE_SIZE); 124 params->bitspersample = 8; 125 params->linethreshold = 0; 126 params->pagetablelistvirt = NULL; 127 params->pagetablelistphys = NULL; 128 params->numpagetableentries = port->hwcfg.buffercount; 129 130 /* Allocate the PCI resources, buffers (hard) */ 131 for (i = 0; i < port->hwcfg.buffercount; i++) { 132 buf = saa7164_buffer_alloc(port, 133 params->numberoflines * 134 params->pitch); 135 136 if (!buf) { 137 printk(KERN_ERR "%s() failed " 138 "(errno = %d), unable to allocate buffer\n", 139 __func__, result); 140 result = -ENOMEM; 141 goto failed; 142 } else { 143 144 mutex_lock(&port->dmaqueue_lock); 145 list_add_tail(&buf->list, &port->dmaqueue.list); 146 mutex_unlock(&port->dmaqueue_lock); 147 148 } 149 } 150 151 /* Allocate some kernel buffers for copying 152 * to userpsace. 153 */ 154 len = params->numberoflines * params->pitch; 155 156 if (vbi_buffers < 16) 157 vbi_buffers = 16; 158 if (vbi_buffers > 512) 159 vbi_buffers = 512; 160 161 for (i = 0; i < vbi_buffers; i++) { 162 163 ubuf = saa7164_buffer_alloc_user(dev, len); 164 if (ubuf) { 165 mutex_lock(&port->dmaqueue_lock); 166 list_add_tail(&ubuf->list, &port->list_buf_free.list); 167 mutex_unlock(&port->dmaqueue_lock); 168 } 169 170 } 171 172 result = 0; 173 174failed: 175 return result; 176} 177 178 179static int saa7164_vbi_initialize(struct saa7164_port *port) 180{ 181 saa7164_vbi_configure(port); 182 return 0; 183} 184 185/* -- V4L2 --------------------------------------------------------- */ 186static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) 187{ 188 struct saa7164_vbi_fh *fh = file->private_data; 189 struct saa7164_port *port = fh->port; 190 struct saa7164_dev *dev = port->dev; 191 unsigned int i; 192 193 dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)id); 194 195 for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { 196 if (id & saa7164_tvnorms[i].id) 197 break; 198 } 199 if (i == ARRAY_SIZE(saa7164_tvnorms)) 200 return -EINVAL; 201 202 port->encodernorm = saa7164_tvnorms[i]; 203 port->std = id; 204 205 /* Update the audio decoder while is not running in 206 * auto detect mode. 207 */ 208 saa7164_api_set_audio_std(port); 209 210 dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)id); 211 212 return 0; 213} 214 215static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) 216{ 217 struct saa7164_encoder_fh *fh = file->private_data; 218 struct saa7164_port *port = fh->port; 219 220 *id = port->std; 221 return 0; 222} 223 224static int vidioc_enum_input(struct file *file, void *priv, 225 struct v4l2_input *i) 226{ 227 int n; 228 229 char *inputs[] = { "tuner", "composite", "svideo", "aux", 230 "composite 2", "svideo 2", "aux 2" }; 231 232 if (i->index >= 7) 233 return -EINVAL; 234 235 strcpy(i->name, inputs[i->index]); 236 237 if (i->index == 0) 238 i->type = V4L2_INPUT_TYPE_TUNER; 239 else 240 i->type = V4L2_INPUT_TYPE_CAMERA; 241 242 for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++) 243 i->std |= saa7164_tvnorms[n].id; 244 245 return 0; 246} 247 248static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) 249{ 250 struct saa7164_vbi_fh *fh = file->private_data; 251 struct saa7164_port *port = fh->port; 252 struct saa7164_dev *dev = port->dev; 253 254 if (saa7164_api_get_videomux(port) != SAA_OK) 255 return -EIO; 256 257 *i = (port->mux_input - 1); 258 259 dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, *i); 260 261 return 0; 262} 263 264static int vidioc_s_input(struct file *file, void *priv, unsigned int i) 265{ 266 struct saa7164_vbi_fh *fh = file->private_data; 267 struct saa7164_port *port = fh->port; 268 struct saa7164_dev *dev = port->dev; 269 270 dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, i); 271 272 if (i >= 7) 273 return -EINVAL; 274 275 port->mux_input = i + 1; 276 277 if (saa7164_api_set_videomux(port) != SAA_OK) 278 return -EIO; 279 280 return 0; 281} 282 283static int vidioc_g_tuner(struct file *file, void *priv, 284 struct v4l2_tuner *t) 285{ 286 struct saa7164_vbi_fh *fh = file->private_data; 287 struct saa7164_port *port = fh->port; 288 struct saa7164_dev *dev = port->dev; 289 290 if (0 != t->index) 291 return -EINVAL; 292 293 strcpy(t->name, "tuner"); 294 t->type = V4L2_TUNER_ANALOG_TV; 295 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO; 296 297 dprintk(DBGLVL_VBI, "VIDIOC_G_TUNER: tuner type %d\n", t->type); 298 299 return 0; 300} 301 302static int vidioc_s_tuner(struct file *file, void *priv, 303 const struct v4l2_tuner *t) 304{ 305 /* Update the A/V core */ 306 return 0; 307} 308 309static int vidioc_g_frequency(struct file *file, void *priv, 310 struct v4l2_frequency *f) 311{ 312 struct saa7164_vbi_fh *fh = file->private_data; 313 struct saa7164_port *port = fh->port; 314 315 f->type = V4L2_TUNER_ANALOG_TV; 316 f->frequency = port->freq; 317 318 return 0; 319} 320 321static int vidioc_s_frequency(struct file *file, void *priv, 322 const struct v4l2_frequency *f) 323{ 324 struct saa7164_vbi_fh *fh = file->private_data; 325 struct saa7164_port *port = fh->port; 326 struct saa7164_dev *dev = port->dev; 327 struct saa7164_port *tsport; 328 struct dvb_frontend *fe; 329 330 /* TODO: Pull this for the std */ 331 struct analog_parameters params = { 332 .mode = V4L2_TUNER_ANALOG_TV, 333 .audmode = V4L2_TUNER_MODE_STEREO, 334 .std = port->encodernorm.id, 335 .frequency = f->frequency 336 }; 337 338 /* Stop the encoder */ 339 dprintk(DBGLVL_VBI, "%s() frequency=%d tuner=%d\n", __func__, 340 f->frequency, f->tuner); 341 342 if (f->tuner != 0) 343 return -EINVAL; 344 345 if (f->type != V4L2_TUNER_ANALOG_TV) 346 return -EINVAL; 347 348 port->freq = f->frequency; 349 350 /* Update the hardware */ 351 if (port->nr == SAA7164_PORT_VBI1) 352 tsport = &dev->ports[SAA7164_PORT_TS1]; 353 else 354 if (port->nr == SAA7164_PORT_VBI2) 355 tsport = &dev->ports[SAA7164_PORT_TS2]; 356 else 357 BUG(); 358 359 fe = tsport->dvb.frontend; 360 361 if (fe && fe->ops.tuner_ops.set_analog_params) 362 fe->ops.tuner_ops.set_analog_params(fe, ¶ms); 363 else 364 printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); 365 366 saa7164_vbi_initialize(port); 367 368 return 0; 369} 370 371static int vidioc_g_ctrl(struct file *file, void *priv, 372 struct v4l2_control *ctl) 373{ 374 struct saa7164_vbi_fh *fh = file->private_data; 375 struct saa7164_port *port = fh->port; 376 struct saa7164_dev *dev = port->dev; 377 378 dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__, 379 ctl->id, ctl->value); 380 381 switch (ctl->id) { 382 case V4L2_CID_BRIGHTNESS: 383 ctl->value = port->ctl_brightness; 384 break; 385 case V4L2_CID_CONTRAST: 386 ctl->value = port->ctl_contrast; 387 break; 388 case V4L2_CID_SATURATION: 389 ctl->value = port->ctl_saturation; 390 break; 391 case V4L2_CID_HUE: 392 ctl->value = port->ctl_hue; 393 break; 394 case V4L2_CID_SHARPNESS: 395 ctl->value = port->ctl_sharpness; 396 break; 397 case V4L2_CID_AUDIO_VOLUME: 398 ctl->value = port->ctl_volume; 399 break; 400 default: 401 return -EINVAL; 402 } 403 404 return 0; 405} 406 407static int vidioc_s_ctrl(struct file *file, void *priv, 408 struct v4l2_control *ctl) 409{ 410 struct saa7164_vbi_fh *fh = file->private_data; 411 struct saa7164_port *port = fh->port; 412 struct saa7164_dev *dev = port->dev; 413 int ret = 0; 414 415 dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__, 416 ctl->id, ctl->value); 417 418 switch (ctl->id) { 419 case V4L2_CID_BRIGHTNESS: 420 if ((ctl->value >= 0) && (ctl->value <= 255)) { 421 port->ctl_brightness = ctl->value; 422 saa7164_api_set_usercontrol(port, 423 PU_BRIGHTNESS_CONTROL); 424 } else 425 ret = -EINVAL; 426 break; 427 case V4L2_CID_CONTRAST: 428 if ((ctl->value >= 0) && (ctl->value <= 255)) { 429 port->ctl_contrast = ctl->value; 430 saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL); 431 } else 432 ret = -EINVAL; 433 break; 434 case V4L2_CID_SATURATION: 435 if ((ctl->value >= 0) && (ctl->value <= 255)) { 436 port->ctl_saturation = ctl->value; 437 saa7164_api_set_usercontrol(port, 438 PU_SATURATION_CONTROL); 439 } else 440 ret = -EINVAL; 441 break; 442 case V4L2_CID_HUE: 443 if ((ctl->value >= 0) && (ctl->value <= 255)) { 444 port->ctl_hue = ctl->value; 445 saa7164_api_set_usercontrol(port, PU_HUE_CONTROL); 446 } else 447 ret = -EINVAL; 448 break; 449 case V4L2_CID_SHARPNESS: 450 if ((ctl->value >= 0) && (ctl->value <= 255)) { 451 port->ctl_sharpness = ctl->value; 452 saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL); 453 } else 454 ret = -EINVAL; 455 break; 456 case V4L2_CID_AUDIO_VOLUME: 457 if ((ctl->value >= -83) && (ctl->value <= 24)) { 458 port->ctl_volume = ctl->value; 459 saa7164_api_set_audio_volume(port, port->ctl_volume); 460 } else 461 ret = -EINVAL; 462 break; 463 default: 464 ret = -EINVAL; 465 } 466 467 return ret; 468} 469 470static int saa7164_get_ctrl(struct saa7164_port *port, 471 struct v4l2_ext_control *ctrl) 472{ 473 struct saa7164_vbi_params *params = &port->vbi_params; 474 475 switch (ctrl->id) { 476 case V4L2_CID_MPEG_STREAM_TYPE: 477 ctrl->value = params->stream_type; 478 break; 479 case V4L2_CID_MPEG_AUDIO_MUTE: 480 ctrl->value = params->ctl_mute; 481 break; 482 case V4L2_CID_MPEG_VIDEO_ASPECT: 483 ctrl->value = params->ctl_aspect; 484 break; 485 case V4L2_CID_MPEG_VIDEO_B_FRAMES: 486 ctrl->value = params->refdist; 487 break; 488 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 489 ctrl->value = params->gop_size; 490 break; 491 default: 492 return -EINVAL; 493 } 494 return 0; 495} 496 497static int vidioc_g_ext_ctrls(struct file *file, void *priv, 498 struct v4l2_ext_controls *ctrls) 499{ 500 struct saa7164_vbi_fh *fh = file->private_data; 501 struct saa7164_port *port = fh->port; 502 int i, err = 0; 503 504 if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { 505 for (i = 0; i < ctrls->count; i++) { 506 struct v4l2_ext_control *ctrl = ctrls->controls + i; 507 508 err = saa7164_get_ctrl(port, ctrl); 509 if (err) { 510 ctrls->error_idx = i; 511 break; 512 } 513 } 514 return err; 515 516 } 517 518 return -EINVAL; 519} 520 521static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3) 522{ 523 int ret = -EINVAL; 524 525 switch (ctrl->id) { 526 case V4L2_CID_MPEG_STREAM_TYPE: 527 if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) || 528 (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)) 529 ret = 0; 530 break; 531 case V4L2_CID_MPEG_AUDIO_MUTE: 532 if ((ctrl->value >= 0) && 533 (ctrl->value <= 1)) 534 ret = 0; 535 break; 536 case V4L2_CID_MPEG_VIDEO_ASPECT: 537 if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) && 538 (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100)) 539 ret = 0; 540 break; 541 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 542 if ((ctrl->value >= 0) && 543 (ctrl->value <= 255)) 544 ret = 0; 545 break; 546 case V4L2_CID_MPEG_VIDEO_B_FRAMES: 547 if ((ctrl->value >= 1) && 548 (ctrl->value <= 3)) 549 ret = 0; 550 break; 551 default: 552 ret = -EINVAL; 553 } 554 555 return ret; 556} 557 558static int vidioc_try_ext_ctrls(struct file *file, void *priv, 559 struct v4l2_ext_controls *ctrls) 560{ 561 int i, err = 0; 562 563 if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { 564 for (i = 0; i < ctrls->count; i++) { 565 struct v4l2_ext_control *ctrl = ctrls->controls + i; 566 567 err = saa7164_try_ctrl(ctrl, 0); 568 if (err) { 569 ctrls->error_idx = i; 570 break; 571 } 572 } 573 return err; 574 } 575 576 return -EINVAL; 577} 578 579static int saa7164_set_ctrl(struct saa7164_port *port, 580 struct v4l2_ext_control *ctrl) 581{ 582 struct saa7164_vbi_params *params = &port->vbi_params; 583 int ret = 0; 584 585 switch (ctrl->id) { 586 case V4L2_CID_MPEG_STREAM_TYPE: 587 params->stream_type = ctrl->value; 588 break; 589 case V4L2_CID_MPEG_AUDIO_MUTE: 590 params->ctl_mute = ctrl->value; 591 ret = saa7164_api_audio_mute(port, params->ctl_mute); 592 if (ret != SAA_OK) { 593 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, 594 ret); 595 ret = -EIO; 596 } 597 break; 598 case V4L2_CID_MPEG_VIDEO_ASPECT: 599 params->ctl_aspect = ctrl->value; 600 ret = saa7164_api_set_aspect_ratio(port); 601 if (ret != SAA_OK) { 602 printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, 603 ret); 604 ret = -EIO; 605 } 606 break; 607 case V4L2_CID_MPEG_VIDEO_B_FRAMES: 608 params->refdist = ctrl->value; 609 break; 610 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 611 params->gop_size = ctrl->value; 612 break; 613 default: 614 return -EINVAL; 615 } 616 617 /* TODO: Update the hardware */ 618 619 return ret; 620} 621 622static int vidioc_s_ext_ctrls(struct file *file, void *priv, 623 struct v4l2_ext_controls *ctrls) 624{ 625 struct saa7164_vbi_fh *fh = file->private_data; 626 struct saa7164_port *port = fh->port; 627 int i, err = 0; 628 629 if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { 630 for (i = 0; i < ctrls->count; i++) { 631 struct v4l2_ext_control *ctrl = ctrls->controls + i; 632 633 err = saa7164_try_ctrl(ctrl, 0); 634 if (err) { 635 ctrls->error_idx = i; 636 break; 637 } 638 err = saa7164_set_ctrl(port, ctrl); 639 if (err) { 640 ctrls->error_idx = i; 641 break; 642 } 643 } 644 return err; 645 646 } 647 648 return -EINVAL; 649} 650 651static int vidioc_querycap(struct file *file, void *priv, 652 struct v4l2_capability *cap) 653{ 654 struct saa7164_vbi_fh *fh = file->private_data; 655 struct saa7164_port *port = fh->port; 656 struct saa7164_dev *dev = port->dev; 657 658 strcpy(cap->driver, dev->name); 659 strlcpy(cap->card, saa7164_boards[dev->board].name, 660 sizeof(cap->card)); 661 sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); 662 663 cap->device_caps = 664 V4L2_CAP_VBI_CAPTURE | 665 V4L2_CAP_READWRITE | 666 V4L2_CAP_TUNER; 667 668 cap->capabilities = cap->device_caps | 669 V4L2_CAP_VIDEO_CAPTURE | 670 V4L2_CAP_DEVICE_CAPS; 671 672 return 0; 673} 674 675static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 676 struct v4l2_fmtdesc *f) 677{ 678 if (f->index != 0) 679 return -EINVAL; 680 681 strlcpy(f->description, "VBI", sizeof(f->description)); 682 f->pixelformat = V4L2_PIX_FMT_MPEG; 683 684 return 0; 685} 686 687static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, 688 struct v4l2_format *f) 689{ 690 struct saa7164_vbi_fh *fh = file->private_data; 691 struct saa7164_port *port = fh->port; 692 struct saa7164_dev *dev = port->dev; 693 694 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 695 f->fmt.pix.bytesperline = 0; 696 f->fmt.pix.sizeimage = 697 port->ts_packet_size * port->ts_packet_count; 698 f->fmt.pix.colorspace = 0; 699 f->fmt.pix.width = port->width; 700 f->fmt.pix.height = port->height; 701 702 dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n", 703 port->width, port->height); 704 705 return 0; 706} 707 708static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 709 struct v4l2_format *f) 710{ 711 struct saa7164_vbi_fh *fh = file->private_data; 712 struct saa7164_port *port = fh->port; 713 struct saa7164_dev *dev = port->dev; 714 715 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 716 f->fmt.pix.bytesperline = 0; 717 f->fmt.pix.sizeimage = 718 port->ts_packet_size * port->ts_packet_count; 719 f->fmt.pix.colorspace = 0; 720 dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n", 721 port->width, port->height); 722 return 0; 723} 724 725static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 726 struct v4l2_format *f) 727{ 728 struct saa7164_vbi_fh *fh = file->private_data; 729 struct saa7164_port *port = fh->port; 730 struct saa7164_dev *dev = port->dev; 731 732 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 733 f->fmt.pix.bytesperline = 0; 734 f->fmt.pix.sizeimage = 735 port->ts_packet_size * port->ts_packet_count; 736 f->fmt.pix.colorspace = 0; 737 738 dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", 739 f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); 740 741 return 0; 742} 743 744static int fill_queryctrl(struct saa7164_vbi_params *params, 745 struct v4l2_queryctrl *c) 746{ 747 switch (c->id) { 748 case V4L2_CID_BRIGHTNESS: 749 return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127); 750 case V4L2_CID_CONTRAST: 751 return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66); 752 case V4L2_CID_SATURATION: 753 return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62); 754 case V4L2_CID_HUE: 755 return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128); 756 case V4L2_CID_SHARPNESS: 757 return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8); 758 case V4L2_CID_MPEG_AUDIO_MUTE: 759 return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0); 760 case V4L2_CID_AUDIO_VOLUME: 761 return v4l2_ctrl_query_fill(c, -83, 24, 1, 20); 762 case V4L2_CID_MPEG_STREAM_TYPE: 763 return v4l2_ctrl_query_fill(c, 764 V4L2_MPEG_STREAM_TYPE_MPEG2_PS, 765 V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 766 1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS); 767 case V4L2_CID_MPEG_VIDEO_ASPECT: 768 return v4l2_ctrl_query_fill(c, 769 V4L2_MPEG_VIDEO_ASPECT_1x1, 770 V4L2_MPEG_VIDEO_ASPECT_221x100, 771 1, V4L2_MPEG_VIDEO_ASPECT_4x3); 772 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 773 return v4l2_ctrl_query_fill(c, 1, 255, 1, 15); 774 case V4L2_CID_MPEG_VIDEO_B_FRAMES: 775 return v4l2_ctrl_query_fill(c, 776 1, 3, 1, 1); 777 default: 778 return -EINVAL; 779 } 780} 781 782static int vidioc_queryctrl(struct file *file, void *priv, 783 struct v4l2_queryctrl *c) 784{ 785 struct saa7164_vbi_fh *fh = priv; 786 struct saa7164_port *port = fh->port; 787 int i, next; 788 u32 id = c->id; 789 790 memset(c, 0, sizeof(*c)); 791 792 next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); 793 c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; 794 795 for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) { 796 if (next) { 797 if (c->id < saa7164_v4l2_ctrls[i]) 798 c->id = saa7164_v4l2_ctrls[i]; 799 else 800 continue; 801 } 802 803 if (c->id == saa7164_v4l2_ctrls[i]) 804 return fill_queryctrl(&port->vbi_params, c); 805 806 if (c->id < saa7164_v4l2_ctrls[i]) 807 break; 808 } 809 810 return -EINVAL; 811} 812 813static int saa7164_vbi_stop_port(struct saa7164_port *port) 814{ 815 struct saa7164_dev *dev = port->dev; 816 int ret; 817 818 ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 819 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 820 printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", 821 __func__, ret); 822 ret = -EIO; 823 } else { 824 dprintk(DBGLVL_VBI, "%s() Stopped\n", __func__); 825 ret = 0; 826 } 827 828 return ret; 829} 830 831static int saa7164_vbi_acquire_port(struct saa7164_port *port) 832{ 833 struct saa7164_dev *dev = port->dev; 834 int ret; 835 836 ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); 837 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 838 printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", 839 __func__, ret); 840 ret = -EIO; 841 } else { 842 dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__); 843 ret = 0; 844 } 845 846 return ret; 847} 848 849static int saa7164_vbi_pause_port(struct saa7164_port *port) 850{ 851 struct saa7164_dev *dev = port->dev; 852 int ret; 853 854 ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); 855 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 856 printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", 857 __func__, ret); 858 ret = -EIO; 859 } else { 860 dprintk(DBGLVL_VBI, "%s() Paused\n", __func__); 861 ret = 0; 862 } 863 864 return ret; 865} 866 867/* Firmware is very windows centric, meaning you have to transition 868 * the part through AVStream / KS Windows stages, forwards or backwards. 869 * States are: stopped, acquired (h/w), paused, started. 870 * We have to leave here will all of the soft buffers on the free list, 871 * else the cfg_post() func won't have soft buffers to correctly configure. 872 */ 873static int saa7164_vbi_stop_streaming(struct saa7164_port *port) 874{ 875 struct saa7164_dev *dev = port->dev; 876 struct saa7164_buffer *buf; 877 struct saa7164_user_buffer *ubuf; 878 struct list_head *c, *n; 879 int ret; 880 881 dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); 882 883 ret = saa7164_vbi_pause_port(port); 884 ret = saa7164_vbi_acquire_port(port); 885 ret = saa7164_vbi_stop_port(port); 886 887 dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__, 888 port->nr); 889 890 /* Reset the state of any allocated buffer resources */ 891 mutex_lock(&port->dmaqueue_lock); 892 893 /* Reset the hard and soft buffer state */ 894 list_for_each_safe(c, n, &port->dmaqueue.list) { 895 buf = list_entry(c, struct saa7164_buffer, list); 896 buf->flags = SAA7164_BUFFER_FREE; 897 buf->pos = 0; 898 } 899 900 list_for_each_safe(c, n, &port->list_buf_used.list) { 901 ubuf = list_entry(c, struct saa7164_user_buffer, list); 902 ubuf->pos = 0; 903 list_move_tail(&ubuf->list, &port->list_buf_free.list); 904 } 905 906 mutex_unlock(&port->dmaqueue_lock); 907 908 /* Free any allocated resources */ 909 saa7164_vbi_buffers_dealloc(port); 910 911 dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr); 912 913 return ret; 914} 915 916static int saa7164_vbi_start_streaming(struct saa7164_port *port) 917{ 918 struct saa7164_dev *dev = port->dev; 919 int result, ret = 0; 920 921 dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); 922 923 port->done_first_interrupt = 0; 924 925 /* allocate all of the PCIe DMA buffer resources on the fly, 926 * allowing switching between TS and PS payloads without 927 * requiring a complete driver reload. 928 */ 929 saa7164_vbi_buffers_alloc(port); 930 931 /* Configure the encoder with any cache values */ 932#if 0 933 saa7164_api_set_encoder(port); 934 saa7164_api_get_encoder(port); 935#endif 936 937 /* Place the empty buffers on the hardware */ 938 saa7164_buffer_cfg_port(port); 939 940 /* Negotiate format */ 941 if (saa7164_api_set_vbi_format(port) != SAA_OK) { 942 printk(KERN_ERR "%s() No supported VBI format\n", __func__); 943 ret = -EIO; 944 goto out; 945 } 946 947 /* Acquire the hardware */ 948 result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); 949 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 950 printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", 951 __func__, result); 952 953 ret = -EIO; 954 goto out; 955 } else 956 dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__); 957 958 /* Pause the hardware */ 959 result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); 960 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 961 printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", 962 __func__, result); 963 964 /* Stop the hardware, regardless */ 965 result = saa7164_vbi_stop_port(port); 966 if (result != SAA_OK) { 967 printk(KERN_ERR "%s() pause/forced stop transition " 968 "failed, res = 0x%x\n", __func__, result); 969 } 970 971 ret = -EIO; 972 goto out; 973 } else 974 dprintk(DBGLVL_VBI, "%s() Paused\n", __func__); 975 976 /* Start the hardware */ 977 result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); 978 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 979 printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", 980 __func__, result); 981 982 /* Stop the hardware, regardless */ 983 result = saa7164_vbi_acquire_port(port); 984 result = saa7164_vbi_stop_port(port); 985 if (result != SAA_OK) { 986 printk(KERN_ERR "%s() run/forced stop transition " 987 "failed, res = 0x%x\n", __func__, result); 988 } 989 990 ret = -EIO; 991 } else 992 dprintk(DBGLVL_VBI, "%s() Running\n", __func__); 993 994out: 995 return ret; 996} 997 998static int saa7164_vbi_fmt(struct file *file, void *priv, 999 struct v4l2_format *f) 1000{ 1001 /* ntsc */ 1002 f->fmt.vbi.samples_per_line = 1600; 1003 f->fmt.vbi.samples_per_line = 1440; 1004 f->fmt.vbi.sampling_rate = 27000000; 1005 f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; 1006 f->fmt.vbi.offset = 0; 1007 f->fmt.vbi.flags = 0; 1008 f->fmt.vbi.start[0] = 10; 1009 f->fmt.vbi.count[0] = 18; 1010 f->fmt.vbi.start[1] = 263 + 10 + 1; 1011 f->fmt.vbi.count[1] = 18; 1012 return 0; 1013} 1014 1015static int fops_open(struct file *file) 1016{ 1017 struct saa7164_dev *dev; 1018 struct saa7164_port *port; 1019 struct saa7164_vbi_fh *fh; 1020 1021 port = (struct saa7164_port *)video_get_drvdata(video_devdata(file)); 1022 if (!port) 1023 return -ENODEV; 1024 1025 dev = port->dev; 1026 1027 dprintk(DBGLVL_VBI, "%s()\n", __func__); 1028 1029 /* allocate + initialize per filehandle data */ 1030 fh = kzalloc(sizeof(*fh), GFP_KERNEL); 1031 if (NULL == fh) 1032 return -ENOMEM; 1033 1034 file->private_data = fh; 1035 fh->port = port; 1036 1037 return 0; 1038} 1039 1040static int fops_release(struct file *file) 1041{ 1042 struct saa7164_vbi_fh *fh = file->private_data; 1043 struct saa7164_port *port = fh->port; 1044 struct saa7164_dev *dev = port->dev; 1045 1046 dprintk(DBGLVL_VBI, "%s()\n", __func__); 1047 1048 /* Shut device down on last close */ 1049 if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { 1050 if (atomic_dec_return(&port->v4l_reader_count) == 0) { 1051 /* stop vbi capture then cancel buffers */ 1052 saa7164_vbi_stop_streaming(port); 1053 } 1054 } 1055 1056 file->private_data = NULL; 1057 kfree(fh); 1058 1059 return 0; 1060} 1061 1062static struct 1063saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) 1064{ 1065 struct saa7164_user_buffer *ubuf = NULL; 1066 struct saa7164_dev *dev = port->dev; 1067 u32 crc; 1068 1069 mutex_lock(&port->dmaqueue_lock); 1070 if (!list_empty(&port->list_buf_used.list)) { 1071 ubuf = list_first_entry(&port->list_buf_used.list, 1072 struct saa7164_user_buffer, list); 1073 1074 if (crc_checking) { 1075 crc = crc32(0, ubuf->data, ubuf->actual_size); 1076 if (crc != ubuf->crc) { 1077 printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", 1078 __func__, 1079 ubuf, ubuf->crc, crc); 1080 } 1081 } 1082 1083 } 1084 mutex_unlock(&port->dmaqueue_lock); 1085 1086 dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf); 1087 1088 return ubuf; 1089} 1090 1091static ssize_t fops_read(struct file *file, char __user *buffer, 1092 size_t count, loff_t *pos) 1093{ 1094 struct saa7164_vbi_fh *fh = file->private_data; 1095 struct saa7164_port *port = fh->port; 1096 struct saa7164_user_buffer *ubuf = NULL; 1097 struct saa7164_dev *dev = port->dev; 1098 int ret = 0; 1099 int rem, cnt; 1100 u8 *p; 1101 1102 port->last_read_msecs_diff = port->last_read_msecs; 1103 port->last_read_msecs = jiffies_to_msecs(jiffies); 1104 port->last_read_msecs_diff = port->last_read_msecs - 1105 port->last_read_msecs_diff; 1106 1107 saa7164_histogram_update(&port->read_interval, 1108 port->last_read_msecs_diff); 1109 1110 if (*pos) { 1111 printk(KERN_ERR "%s() ESPIPE\n", __func__); 1112 return -ESPIPE; 1113 } 1114 1115 if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { 1116 if (atomic_inc_return(&port->v4l_reader_count) == 1) { 1117 1118 if (saa7164_vbi_initialize(port) < 0) { 1119 printk(KERN_ERR "%s() EINVAL\n", __func__); 1120 return -EINVAL; 1121 } 1122 1123 saa7164_vbi_start_streaming(port); 1124 msleep(200); 1125 } 1126 } 1127 1128 /* blocking wait for buffer */ 1129 if ((file->f_flags & O_NONBLOCK) == 0) { 1130 if (wait_event_interruptible(port->wait_read, 1131 saa7164_vbi_next_buf(port))) { 1132 printk(KERN_ERR "%s() ERESTARTSYS\n", __func__); 1133 return -ERESTARTSYS; 1134 } 1135 } 1136 1137 /* Pull the first buffer from the used list */ 1138 ubuf = saa7164_vbi_next_buf(port); 1139 1140 while ((count > 0) && ubuf) { 1141 1142 /* set remaining bytes to copy */ 1143 rem = ubuf->actual_size - ubuf->pos; 1144 cnt = rem > count ? count : rem; 1145 1146 p = ubuf->data + ubuf->pos; 1147 1148 dprintk(DBGLVL_VBI, 1149 "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n", 1150 __func__, (int)count, cnt, rem, ubuf, ubuf->pos); 1151 1152 if (copy_to_user(buffer, p, cnt)) { 1153 printk(KERN_ERR "%s() copy_to_user failed\n", __func__); 1154 if (!ret) { 1155 printk(KERN_ERR "%s() EFAULT\n", __func__); 1156 ret = -EFAULT; 1157 } 1158 goto err; 1159 } 1160 1161 ubuf->pos += cnt; 1162 count -= cnt; 1163 buffer += cnt; 1164 ret += cnt; 1165 1166 if (ubuf->pos > ubuf->actual_size) 1167 printk(KERN_ERR "read() pos > actual, huh?\n"); 1168 1169 if (ubuf->pos == ubuf->actual_size) { 1170 1171 /* finished with current buffer, take next buffer */ 1172 1173 /* Requeue the buffer on the free list */ 1174 ubuf->pos = 0; 1175 1176 mutex_lock(&port->dmaqueue_lock); 1177 list_move_tail(&ubuf->list, &port->list_buf_free.list); 1178 mutex_unlock(&port->dmaqueue_lock); 1179 1180 /* Dequeue next */ 1181 if ((file->f_flags & O_NONBLOCK) == 0) { 1182 if (wait_event_interruptible(port->wait_read, 1183 saa7164_vbi_next_buf(port))) { 1184 break; 1185 } 1186 } 1187 ubuf = saa7164_vbi_next_buf(port); 1188 } 1189 } 1190err: 1191 if (!ret && !ubuf) { 1192 printk(KERN_ERR "%s() EAGAIN\n", __func__); 1193 ret = -EAGAIN; 1194 } 1195 1196 return ret; 1197} 1198 1199static unsigned int fops_poll(struct file *file, poll_table *wait) 1200{ 1201 struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data; 1202 struct saa7164_port *port = fh->port; 1203 unsigned int mask = 0; 1204 1205 port->last_poll_msecs_diff = port->last_poll_msecs; 1206 port->last_poll_msecs = jiffies_to_msecs(jiffies); 1207 port->last_poll_msecs_diff = port->last_poll_msecs - 1208 port->last_poll_msecs_diff; 1209 1210 saa7164_histogram_update(&port->poll_interval, 1211 port->last_poll_msecs_diff); 1212 1213 if (!video_is_registered(port->v4l_device)) 1214 return -EIO; 1215 1216 if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { 1217 if (atomic_inc_return(&port->v4l_reader_count) == 1) { 1218 if (saa7164_vbi_initialize(port) < 0) 1219 return -EINVAL; 1220 saa7164_vbi_start_streaming(port); 1221 msleep(200); 1222 } 1223 } 1224 1225 /* blocking wait for buffer */ 1226 if ((file->f_flags & O_NONBLOCK) == 0) { 1227 if (wait_event_interruptible(port->wait_read, 1228 saa7164_vbi_next_buf(port))) { 1229 return -ERESTARTSYS; 1230 } 1231 } 1232 1233 /* Pull the first buffer from the used list */ 1234 if (!list_empty(&port->list_buf_used.list)) 1235 mask |= POLLIN | POLLRDNORM; 1236 1237 return mask; 1238} 1239static const struct v4l2_file_operations vbi_fops = { 1240 .owner = THIS_MODULE, 1241 .open = fops_open, 1242 .release = fops_release, 1243 .read = fops_read, 1244 .poll = fops_poll, 1245 .unlocked_ioctl = video_ioctl2, 1246}; 1247 1248static const struct v4l2_ioctl_ops vbi_ioctl_ops = { 1249 .vidioc_s_std = vidioc_s_std, 1250 .vidioc_g_std = vidioc_g_std, 1251 .vidioc_enum_input = vidioc_enum_input, 1252 .vidioc_g_input = vidioc_g_input, 1253 .vidioc_s_input = vidioc_s_input, 1254 .vidioc_g_tuner = vidioc_g_tuner, 1255 .vidioc_s_tuner = vidioc_s_tuner, 1256 .vidioc_g_frequency = vidioc_g_frequency, 1257 .vidioc_s_frequency = vidioc_s_frequency, 1258 .vidioc_s_ctrl = vidioc_s_ctrl, 1259 .vidioc_g_ctrl = vidioc_g_ctrl, 1260 .vidioc_querycap = vidioc_querycap, 1261 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 1262 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 1263 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, 1264 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, 1265 .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, 1266 .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, 1267 .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, 1268 .vidioc_queryctrl = vidioc_queryctrl, 1269 .vidioc_g_fmt_vbi_cap = saa7164_vbi_fmt, 1270 .vidioc_try_fmt_vbi_cap = saa7164_vbi_fmt, 1271 .vidioc_s_fmt_vbi_cap = saa7164_vbi_fmt, 1272}; 1273 1274static struct video_device saa7164_vbi_template = { 1275 .name = "saa7164", 1276 .fops = &vbi_fops, 1277 .ioctl_ops = &vbi_ioctl_ops, 1278 .minor = -1, 1279 .tvnorms = SAA7164_NORMS, 1280}; 1281 1282static struct video_device *saa7164_vbi_alloc( 1283 struct saa7164_port *port, 1284 struct pci_dev *pci, 1285 struct video_device *template, 1286 char *type) 1287{ 1288 struct video_device *vfd; 1289 struct saa7164_dev *dev = port->dev; 1290 1291 dprintk(DBGLVL_VBI, "%s()\n", __func__); 1292 1293 vfd = video_device_alloc(); 1294 if (NULL == vfd) 1295 return NULL; 1296 1297 *vfd = *template; 1298 snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, 1299 type, saa7164_boards[dev->board].name); 1300 1301 vfd->v4l2_dev = &dev->v4l2_dev; 1302 vfd->release = video_device_release; 1303 return vfd; 1304} 1305 1306int saa7164_vbi_register(struct saa7164_port *port) 1307{ 1308 struct saa7164_dev *dev = port->dev; 1309 int result = -ENODEV; 1310 1311 dprintk(DBGLVL_VBI, "%s()\n", __func__); 1312 1313 if (port->type != SAA7164_MPEG_VBI) 1314 BUG(); 1315 1316 /* Sanity check that the PCI configuration space is active */ 1317 if (port->hwcfg.BARLocation == 0) { 1318 printk(KERN_ERR "%s() failed " 1319 "(errno = %d), NO PCI configuration\n", 1320 __func__, result); 1321 result = -ENOMEM; 1322 goto failed; 1323 } 1324 1325 /* Establish VBI defaults here */ 1326 1327 /* Allocate and register the video device node */ 1328 port->v4l_device = saa7164_vbi_alloc(port, 1329 dev->pci, &saa7164_vbi_template, "vbi"); 1330 1331 if (!port->v4l_device) { 1332 printk(KERN_INFO "%s: can't allocate vbi device\n", 1333 dev->name); 1334 result = -ENOMEM; 1335 goto failed; 1336 } 1337 1338 port->std = V4L2_STD_NTSC_M; 1339 video_set_drvdata(port->v4l_device, port); 1340 result = video_register_device(port->v4l_device, 1341 VFL_TYPE_VBI, -1); 1342 if (result < 0) { 1343 printk(KERN_INFO "%s: can't register vbi device\n", 1344 dev->name); 1345 /* TODO: We're going to leak here if we don't dealloc 1346 The buffers above. The unreg function can't deal wit it. 1347 */ 1348 goto failed; 1349 } 1350 1351 printk(KERN_INFO "%s: registered device vbi%d [vbi]\n", 1352 dev->name, port->v4l_device->num); 1353 1354 /* Configure the hardware defaults */ 1355 1356 result = 0; 1357failed: 1358 return result; 1359} 1360 1361void saa7164_vbi_unregister(struct saa7164_port *port) 1362{ 1363 struct saa7164_dev *dev = port->dev; 1364 1365 dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); 1366 1367 if (port->type != SAA7164_MPEG_VBI) 1368 BUG(); 1369 1370 if (port->v4l_device) { 1371 if (port->v4l_device->minor != -1) 1372 video_unregister_device(port->v4l_device); 1373 else 1374 video_device_release(port->v4l_device); 1375 1376 port->v4l_device = NULL; 1377 } 1378 1379} 1380