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->capabilities = 664 V4L2_CAP_VBI_CAPTURE | 665 V4L2_CAP_READWRITE | 666 0; 667 668 cap->capabilities |= V4L2_CAP_TUNER; 669 cap->version = 0; 670 671 return 0; 672} 673 674static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 675 struct v4l2_fmtdesc *f) 676{ 677 if (f->index != 0) 678 return -EINVAL; 679 680 strlcpy(f->description, "VBI", sizeof(f->description)); 681 f->pixelformat = V4L2_PIX_FMT_MPEG; 682 683 return 0; 684} 685 686static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, 687 struct v4l2_format *f) 688{ 689 struct saa7164_vbi_fh *fh = file->private_data; 690 struct saa7164_port *port = fh->port; 691 struct saa7164_dev *dev = port->dev; 692 693 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 694 f->fmt.pix.bytesperline = 0; 695 f->fmt.pix.sizeimage = 696 port->ts_packet_size * port->ts_packet_count; 697 f->fmt.pix.colorspace = 0; 698 f->fmt.pix.width = port->width; 699 f->fmt.pix.height = port->height; 700 701 dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n", 702 port->width, port->height); 703 704 return 0; 705} 706 707static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 708 struct v4l2_format *f) 709{ 710 struct saa7164_vbi_fh *fh = file->private_data; 711 struct saa7164_port *port = fh->port; 712 struct saa7164_dev *dev = port->dev; 713 714 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 715 f->fmt.pix.bytesperline = 0; 716 f->fmt.pix.sizeimage = 717 port->ts_packet_size * port->ts_packet_count; 718 f->fmt.pix.colorspace = 0; 719 dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n", 720 port->width, port->height); 721 return 0; 722} 723 724static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 725 struct v4l2_format *f) 726{ 727 struct saa7164_vbi_fh *fh = file->private_data; 728 struct saa7164_port *port = fh->port; 729 struct saa7164_dev *dev = port->dev; 730 731 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 732 f->fmt.pix.bytesperline = 0; 733 f->fmt.pix.sizeimage = 734 port->ts_packet_size * port->ts_packet_count; 735 f->fmt.pix.colorspace = 0; 736 737 dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", 738 f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); 739 740 return 0; 741} 742 743static int fill_queryctrl(struct saa7164_vbi_params *params, 744 struct v4l2_queryctrl *c) 745{ 746 switch (c->id) { 747 case V4L2_CID_BRIGHTNESS: 748 return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127); 749 case V4L2_CID_CONTRAST: 750 return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66); 751 case V4L2_CID_SATURATION: 752 return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62); 753 case V4L2_CID_HUE: 754 return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128); 755 case V4L2_CID_SHARPNESS: 756 return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8); 757 case V4L2_CID_MPEG_AUDIO_MUTE: 758 return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0); 759 case V4L2_CID_AUDIO_VOLUME: 760 return v4l2_ctrl_query_fill(c, -83, 24, 1, 20); 761 case V4L2_CID_MPEG_STREAM_TYPE: 762 return v4l2_ctrl_query_fill(c, 763 V4L2_MPEG_STREAM_TYPE_MPEG2_PS, 764 V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 765 1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS); 766 case V4L2_CID_MPEG_VIDEO_ASPECT: 767 return v4l2_ctrl_query_fill(c, 768 V4L2_MPEG_VIDEO_ASPECT_1x1, 769 V4L2_MPEG_VIDEO_ASPECT_221x100, 770 1, V4L2_MPEG_VIDEO_ASPECT_4x3); 771 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 772 return v4l2_ctrl_query_fill(c, 1, 255, 1, 15); 773 case V4L2_CID_MPEG_VIDEO_B_FRAMES: 774 return v4l2_ctrl_query_fill(c, 775 1, 3, 1, 1); 776 default: 777 return -EINVAL; 778 } 779} 780 781static int vidioc_queryctrl(struct file *file, void *priv, 782 struct v4l2_queryctrl *c) 783{ 784 struct saa7164_vbi_fh *fh = priv; 785 struct saa7164_port *port = fh->port; 786 int i, next; 787 u32 id = c->id; 788 789 memset(c, 0, sizeof(*c)); 790 791 next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); 792 c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; 793 794 for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) { 795 if (next) { 796 if (c->id < saa7164_v4l2_ctrls[i]) 797 c->id = saa7164_v4l2_ctrls[i]; 798 else 799 continue; 800 } 801 802 if (c->id == saa7164_v4l2_ctrls[i]) 803 return fill_queryctrl(&port->vbi_params, c); 804 805 if (c->id < saa7164_v4l2_ctrls[i]) 806 break; 807 } 808 809 return -EINVAL; 810} 811 812static int saa7164_vbi_stop_port(struct saa7164_port *port) 813{ 814 struct saa7164_dev *dev = port->dev; 815 int ret; 816 817 ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 818 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 819 printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", 820 __func__, ret); 821 ret = -EIO; 822 } else { 823 dprintk(DBGLVL_VBI, "%s() Stopped\n", __func__); 824 ret = 0; 825 } 826 827 return ret; 828} 829 830static int saa7164_vbi_acquire_port(struct saa7164_port *port) 831{ 832 struct saa7164_dev *dev = port->dev; 833 int ret; 834 835 ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); 836 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 837 printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", 838 __func__, ret); 839 ret = -EIO; 840 } else { 841 dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__); 842 ret = 0; 843 } 844 845 return ret; 846} 847 848static int saa7164_vbi_pause_port(struct saa7164_port *port) 849{ 850 struct saa7164_dev *dev = port->dev; 851 int ret; 852 853 ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); 854 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 855 printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", 856 __func__, ret); 857 ret = -EIO; 858 } else { 859 dprintk(DBGLVL_VBI, "%s() Paused\n", __func__); 860 ret = 0; 861 } 862 863 return ret; 864} 865 866/* Firmware is very windows centric, meaning you have to transition 867 * the part through AVStream / KS Windows stages, forwards or backwards. 868 * States are: stopped, acquired (h/w), paused, started. 869 * We have to leave here will all of the soft buffers on the free list, 870 * else the cfg_post() func won't have soft buffers to correctly configure. 871 */ 872static int saa7164_vbi_stop_streaming(struct saa7164_port *port) 873{ 874 struct saa7164_dev *dev = port->dev; 875 struct saa7164_buffer *buf; 876 struct saa7164_user_buffer *ubuf; 877 struct list_head *c, *n; 878 int ret; 879 880 dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); 881 882 ret = saa7164_vbi_pause_port(port); 883 ret = saa7164_vbi_acquire_port(port); 884 ret = saa7164_vbi_stop_port(port); 885 886 dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__, 887 port->nr); 888 889 /* Reset the state of any allocated buffer resources */ 890 mutex_lock(&port->dmaqueue_lock); 891 892 /* Reset the hard and soft buffer state */ 893 list_for_each_safe(c, n, &port->dmaqueue.list) { 894 buf = list_entry(c, struct saa7164_buffer, list); 895 buf->flags = SAA7164_BUFFER_FREE; 896 buf->pos = 0; 897 } 898 899 list_for_each_safe(c, n, &port->list_buf_used.list) { 900 ubuf = list_entry(c, struct saa7164_user_buffer, list); 901 ubuf->pos = 0; 902 list_move_tail(&ubuf->list, &port->list_buf_free.list); 903 } 904 905 mutex_unlock(&port->dmaqueue_lock); 906 907 /* Free any allocated resources */ 908 saa7164_vbi_buffers_dealloc(port); 909 910 dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr); 911 912 return ret; 913} 914 915static int saa7164_vbi_start_streaming(struct saa7164_port *port) 916{ 917 struct saa7164_dev *dev = port->dev; 918 int result, ret = 0; 919 920 dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); 921 922 port->done_first_interrupt = 0; 923 924 /* allocate all of the PCIe DMA buffer resources on the fly, 925 * allowing switching between TS and PS payloads without 926 * requiring a complete driver reload. 927 */ 928 saa7164_vbi_buffers_alloc(port); 929 930 /* Configure the encoder with any cache values */ 931#if 0 932 saa7164_api_set_encoder(port); 933 saa7164_api_get_encoder(port); 934#endif 935 936 /* Place the empty buffers on the hardware */ 937 saa7164_buffer_cfg_port(port); 938 939 /* Negotiate format */ 940 if (saa7164_api_set_vbi_format(port) != SAA_OK) { 941 printk(KERN_ERR "%s() No supported VBI format\n", __func__); 942 ret = -EIO; 943 goto out; 944 } 945 946 /* Acquire the hardware */ 947 result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); 948 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 949 printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", 950 __func__, result); 951 952 ret = -EIO; 953 goto out; 954 } else 955 dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__); 956 957 /* Pause the hardware */ 958 result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); 959 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 960 printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", 961 __func__, result); 962 963 /* Stop the hardware, regardless */ 964 result = saa7164_vbi_stop_port(port); 965 if (result != SAA_OK) { 966 printk(KERN_ERR "%s() pause/forced stop transition " 967 "failed, res = 0x%x\n", __func__, result); 968 } 969 970 ret = -EIO; 971 goto out; 972 } else 973 dprintk(DBGLVL_VBI, "%s() Paused\n", __func__); 974 975 /* Start the hardware */ 976 result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); 977 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 978 printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", 979 __func__, result); 980 981 /* Stop the hardware, regardless */ 982 result = saa7164_vbi_acquire_port(port); 983 result = saa7164_vbi_stop_port(port); 984 if (result != SAA_OK) { 985 printk(KERN_ERR "%s() run/forced stop transition " 986 "failed, res = 0x%x\n", __func__, result); 987 } 988 989 ret = -EIO; 990 } else 991 dprintk(DBGLVL_VBI, "%s() Running\n", __func__); 992 993out: 994 return ret; 995} 996 997static int saa7164_vbi_fmt(struct file *file, void *priv, 998 struct v4l2_format *f) 999{ 1000 /* ntsc */ 1001 f->fmt.vbi.samples_per_line = 1600; 1002 f->fmt.vbi.samples_per_line = 1440; 1003 f->fmt.vbi.sampling_rate = 27000000; 1004 f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; 1005 f->fmt.vbi.offset = 0; 1006 f->fmt.vbi.flags = 0; 1007 f->fmt.vbi.start[0] = 10; 1008 f->fmt.vbi.count[0] = 18; 1009 f->fmt.vbi.start[1] = 263 + 10 + 1; 1010 f->fmt.vbi.count[1] = 18; 1011 return 0; 1012} 1013 1014static int fops_open(struct file *file) 1015{ 1016 struct saa7164_dev *dev; 1017 struct saa7164_port *port; 1018 struct saa7164_vbi_fh *fh; 1019 1020 port = (struct saa7164_port *)video_get_drvdata(video_devdata(file)); 1021 if (!port) 1022 return -ENODEV; 1023 1024 dev = port->dev; 1025 1026 dprintk(DBGLVL_VBI, "%s()\n", __func__); 1027 1028 /* allocate + initialize per filehandle data */ 1029 fh = kzalloc(sizeof(*fh), GFP_KERNEL); 1030 if (NULL == fh) 1031 return -ENOMEM; 1032 1033 file->private_data = fh; 1034 fh->port = port; 1035 1036 return 0; 1037} 1038 1039static int fops_release(struct file *file) 1040{ 1041 struct saa7164_vbi_fh *fh = file->private_data; 1042 struct saa7164_port *port = fh->port; 1043 struct saa7164_dev *dev = port->dev; 1044 1045 dprintk(DBGLVL_VBI, "%s()\n", __func__); 1046 1047 /* Shut device down on last close */ 1048 if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { 1049 if (atomic_dec_return(&port->v4l_reader_count) == 0) { 1050 /* stop vbi capture then cancel buffers */ 1051 saa7164_vbi_stop_streaming(port); 1052 } 1053 } 1054 1055 file->private_data = NULL; 1056 kfree(fh); 1057 1058 return 0; 1059} 1060 1061static struct 1062saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) 1063{ 1064 struct saa7164_user_buffer *ubuf = NULL; 1065 struct saa7164_dev *dev = port->dev; 1066 u32 crc; 1067 1068 mutex_lock(&port->dmaqueue_lock); 1069 if (!list_empty(&port->list_buf_used.list)) { 1070 ubuf = list_first_entry(&port->list_buf_used.list, 1071 struct saa7164_user_buffer, list); 1072 1073 if (crc_checking) { 1074 crc = crc32(0, ubuf->data, ubuf->actual_size); 1075 if (crc != ubuf->crc) { 1076 printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", 1077 __func__, 1078 ubuf, ubuf->crc, crc); 1079 } 1080 } 1081 1082 } 1083 mutex_unlock(&port->dmaqueue_lock); 1084 1085 dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf); 1086 1087 return ubuf; 1088} 1089 1090static ssize_t fops_read(struct file *file, char __user *buffer, 1091 size_t count, loff_t *pos) 1092{ 1093 struct saa7164_vbi_fh *fh = file->private_data; 1094 struct saa7164_port *port = fh->port; 1095 struct saa7164_user_buffer *ubuf = NULL; 1096 struct saa7164_dev *dev = port->dev; 1097 int ret = 0; 1098 int rem, cnt; 1099 u8 *p; 1100 1101 port->last_read_msecs_diff = port->last_read_msecs; 1102 port->last_read_msecs = jiffies_to_msecs(jiffies); 1103 port->last_read_msecs_diff = port->last_read_msecs - 1104 port->last_read_msecs_diff; 1105 1106 saa7164_histogram_update(&port->read_interval, 1107 port->last_read_msecs_diff); 1108 1109 if (*pos) { 1110 printk(KERN_ERR "%s() ESPIPE\n", __func__); 1111 return -ESPIPE; 1112 } 1113 1114 if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { 1115 if (atomic_inc_return(&port->v4l_reader_count) == 1) { 1116 1117 if (saa7164_vbi_initialize(port) < 0) { 1118 printk(KERN_ERR "%s() EINVAL\n", __func__); 1119 return -EINVAL; 1120 } 1121 1122 saa7164_vbi_start_streaming(port); 1123 msleep(200); 1124 } 1125 } 1126 1127 /* blocking wait for buffer */ 1128 if ((file->f_flags & O_NONBLOCK) == 0) { 1129 if (wait_event_interruptible(port->wait_read, 1130 saa7164_vbi_next_buf(port))) { 1131 printk(KERN_ERR "%s() ERESTARTSYS\n", __func__); 1132 return -ERESTARTSYS; 1133 } 1134 } 1135 1136 /* Pull the first buffer from the used list */ 1137 ubuf = saa7164_vbi_next_buf(port); 1138 1139 while ((count > 0) && ubuf) { 1140 1141 /* set remaining bytes to copy */ 1142 rem = ubuf->actual_size - ubuf->pos; 1143 cnt = rem > count ? count : rem; 1144 1145 p = ubuf->data + ubuf->pos; 1146 1147 dprintk(DBGLVL_VBI, 1148 "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n", 1149 __func__, (int)count, cnt, rem, ubuf, ubuf->pos); 1150 1151 if (copy_to_user(buffer, p, cnt)) { 1152 printk(KERN_ERR "%s() copy_to_user failed\n", __func__); 1153 if (!ret) { 1154 printk(KERN_ERR "%s() EFAULT\n", __func__); 1155 ret = -EFAULT; 1156 } 1157 goto err; 1158 } 1159 1160 ubuf->pos += cnt; 1161 count -= cnt; 1162 buffer += cnt; 1163 ret += cnt; 1164 1165 if (ubuf->pos > ubuf->actual_size) 1166 printk(KERN_ERR "read() pos > actual, huh?\n"); 1167 1168 if (ubuf->pos == ubuf->actual_size) { 1169 1170 /* finished with current buffer, take next buffer */ 1171 1172 /* Requeue the buffer on the free list */ 1173 ubuf->pos = 0; 1174 1175 mutex_lock(&port->dmaqueue_lock); 1176 list_move_tail(&ubuf->list, &port->list_buf_free.list); 1177 mutex_unlock(&port->dmaqueue_lock); 1178 1179 /* Dequeue next */ 1180 if ((file->f_flags & O_NONBLOCK) == 0) { 1181 if (wait_event_interruptible(port->wait_read, 1182 saa7164_vbi_next_buf(port))) { 1183 break; 1184 } 1185 } 1186 ubuf = saa7164_vbi_next_buf(port); 1187 } 1188 } 1189err: 1190 if (!ret && !ubuf) { 1191 printk(KERN_ERR "%s() EAGAIN\n", __func__); 1192 ret = -EAGAIN; 1193 } 1194 1195 return ret; 1196} 1197 1198static unsigned int fops_poll(struct file *file, poll_table *wait) 1199{ 1200 struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data; 1201 struct saa7164_port *port = fh->port; 1202 unsigned int mask = 0; 1203 1204 port->last_poll_msecs_diff = port->last_poll_msecs; 1205 port->last_poll_msecs = jiffies_to_msecs(jiffies); 1206 port->last_poll_msecs_diff = port->last_poll_msecs - 1207 port->last_poll_msecs_diff; 1208 1209 saa7164_histogram_update(&port->poll_interval, 1210 port->last_poll_msecs_diff); 1211 1212 if (!video_is_registered(port->v4l_device)) 1213 return -EIO; 1214 1215 if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { 1216 if (atomic_inc_return(&port->v4l_reader_count) == 1) { 1217 if (saa7164_vbi_initialize(port) < 0) 1218 return -EINVAL; 1219 saa7164_vbi_start_streaming(port); 1220 msleep(200); 1221 } 1222 } 1223 1224 /* blocking wait for buffer */ 1225 if ((file->f_flags & O_NONBLOCK) == 0) { 1226 if (wait_event_interruptible(port->wait_read, 1227 saa7164_vbi_next_buf(port))) { 1228 return -ERESTARTSYS; 1229 } 1230 } 1231 1232 /* Pull the first buffer from the used list */ 1233 if (!list_empty(&port->list_buf_used.list)) 1234 mask |= POLLIN | POLLRDNORM; 1235 1236 return mask; 1237} 1238static const struct v4l2_file_operations vbi_fops = { 1239 .owner = THIS_MODULE, 1240 .open = fops_open, 1241 .release = fops_release, 1242 .read = fops_read, 1243 .poll = fops_poll, 1244 .unlocked_ioctl = video_ioctl2, 1245}; 1246 1247static const struct v4l2_ioctl_ops vbi_ioctl_ops = { 1248 .vidioc_s_std = vidioc_s_std, 1249 .vidioc_g_std = vidioc_g_std, 1250 .vidioc_enum_input = vidioc_enum_input, 1251 .vidioc_g_input = vidioc_g_input, 1252 .vidioc_s_input = vidioc_s_input, 1253 .vidioc_g_tuner = vidioc_g_tuner, 1254 .vidioc_s_tuner = vidioc_s_tuner, 1255 .vidioc_g_frequency = vidioc_g_frequency, 1256 .vidioc_s_frequency = vidioc_s_frequency, 1257 .vidioc_s_ctrl = vidioc_s_ctrl, 1258 .vidioc_g_ctrl = vidioc_g_ctrl, 1259 .vidioc_querycap = vidioc_querycap, 1260 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 1261 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 1262 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, 1263 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, 1264 .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, 1265 .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, 1266 .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, 1267 .vidioc_queryctrl = vidioc_queryctrl, 1268 .vidioc_g_fmt_vbi_cap = saa7164_vbi_fmt, 1269 .vidioc_try_fmt_vbi_cap = saa7164_vbi_fmt, 1270 .vidioc_s_fmt_vbi_cap = saa7164_vbi_fmt, 1271}; 1272 1273static struct video_device saa7164_vbi_template = { 1274 .name = "saa7164", 1275 .fops = &vbi_fops, 1276 .ioctl_ops = &vbi_ioctl_ops, 1277 .minor = -1, 1278 .tvnorms = SAA7164_NORMS, 1279}; 1280 1281static struct video_device *saa7164_vbi_alloc( 1282 struct saa7164_port *port, 1283 struct pci_dev *pci, 1284 struct video_device *template, 1285 char *type) 1286{ 1287 struct video_device *vfd; 1288 struct saa7164_dev *dev = port->dev; 1289 1290 dprintk(DBGLVL_VBI, "%s()\n", __func__); 1291 1292 vfd = video_device_alloc(); 1293 if (NULL == vfd) 1294 return NULL; 1295 1296 *vfd = *template; 1297 snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, 1298 type, saa7164_boards[dev->board].name); 1299 1300 vfd->v4l2_dev = &dev->v4l2_dev; 1301 vfd->release = video_device_release; 1302 return vfd; 1303} 1304 1305int saa7164_vbi_register(struct saa7164_port *port) 1306{ 1307 struct saa7164_dev *dev = port->dev; 1308 int result = -ENODEV; 1309 1310 dprintk(DBGLVL_VBI, "%s()\n", __func__); 1311 1312 if (port->type != SAA7164_MPEG_VBI) 1313 BUG(); 1314 1315 /* Sanity check that the PCI configuration space is active */ 1316 if (port->hwcfg.BARLocation == 0) { 1317 printk(KERN_ERR "%s() failed " 1318 "(errno = %d), NO PCI configuration\n", 1319 __func__, result); 1320 result = -ENOMEM; 1321 goto failed; 1322 } 1323 1324 /* Establish VBI defaults here */ 1325 1326 /* Allocate and register the video device node */ 1327 port->v4l_device = saa7164_vbi_alloc(port, 1328 dev->pci, &saa7164_vbi_template, "vbi"); 1329 1330 if (!port->v4l_device) { 1331 printk(KERN_INFO "%s: can't allocate vbi device\n", 1332 dev->name); 1333 result = -ENOMEM; 1334 goto failed; 1335 } 1336 1337 port->std = V4L2_STD_NTSC_M; 1338 video_set_drvdata(port->v4l_device, port); 1339 result = video_register_device(port->v4l_device, 1340 VFL_TYPE_VBI, -1); 1341 if (result < 0) { 1342 printk(KERN_INFO "%s: can't register vbi device\n", 1343 dev->name); 1344 /* TODO: We're going to leak here if we don't dealloc 1345 The buffers above. The unreg function can't deal wit it. 1346 */ 1347 goto failed; 1348 } 1349 1350 printk(KERN_INFO "%s: registered device vbi%d [vbi]\n", 1351 dev->name, port->v4l_device->num); 1352 1353 /* Configure the hardware defaults */ 1354 1355 result = 0; 1356failed: 1357 return result; 1358} 1359 1360void saa7164_vbi_unregister(struct saa7164_port *port) 1361{ 1362 struct saa7164_dev *dev = port->dev; 1363 1364 dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); 1365 1366 if (port->type != SAA7164_MPEG_VBI) 1367 BUG(); 1368 1369 if (port->v4l_device) { 1370 if (port->v4l_device->minor != -1) 1371 video_unregister_device(port->v4l_device); 1372 else 1373 video_device_release(port->v4l_device); 1374 1375 port->v4l_device = NULL; 1376 } 1377 1378} 1379