0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include "ivtv-driver.h"
0030 #include "ivtv-cards.h"
0031 #include "ivtv-i2c.h"
0032 #include "ivtv-udma.h"
0033 #include "ivtv-mailbox.h"
0034 #include "ivtv-firmware.h"
0035
0036 #include <linux/fb.h>
0037 #include <linux/ivtvfb.h>
0038
0039 #if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
0040 #include <asm/memtype.h>
0041 #endif
0042
0043
0044 static int ivtvfb_card_id = -1;
0045 static int ivtvfb_debug;
0046 static bool ivtvfb_force_pat = IS_ENABLED(CONFIG_VIDEO_FB_IVTV_FORCE_PAT);
0047 static bool osd_laced;
0048 static int osd_depth;
0049 static int osd_upper;
0050 static int osd_left;
0051 static unsigned int osd_yres;
0052 static unsigned int osd_xres;
0053
0054 module_param(ivtvfb_card_id, int, 0444);
0055 module_param_named(debug,ivtvfb_debug, int, 0644);
0056 module_param_named(force_pat, ivtvfb_force_pat, bool, 0644);
0057 module_param(osd_laced, bool, 0444);
0058 module_param(osd_depth, int, 0444);
0059 module_param(osd_upper, int, 0444);
0060 module_param(osd_left, int, 0444);
0061 module_param(osd_yres, uint, 0444);
0062 module_param(osd_xres, uint, 0444);
0063
0064 MODULE_PARM_DESC(ivtvfb_card_id,
0065 "Only use framebuffer of the specified ivtv card (0-31)\n"
0066 "\t\t\tdefault -1: initialize all available framebuffers");
0067
0068 MODULE_PARM_DESC(debug,
0069 "Debug level (bitmask). Default: errors only\n"
0070 "\t\t\t(debug = 3 gives full debugging)");
0071
0072 MODULE_PARM_DESC(force_pat,
0073 "Force initialization on x86 PAT-enabled systems (bool).\n");
0074
0075
0076
0077
0078
0079 MODULE_PARM_DESC(osd_laced,
0080 "Interlaced mode\n"
0081 "\t\t\t0=off\n"
0082 "\t\t\t1=on\n"
0083 "\t\t\tdefault off");
0084
0085 MODULE_PARM_DESC(osd_depth,
0086 "Bits per pixel - 8, 16, 32\n"
0087 "\t\t\tdefault 8");
0088
0089 MODULE_PARM_DESC(osd_upper,
0090 "Vertical start position\n"
0091 "\t\t\tdefault 0 (Centered)");
0092
0093 MODULE_PARM_DESC(osd_left,
0094 "Horizontal start position\n"
0095 "\t\t\tdefault 0 (Centered)");
0096
0097 MODULE_PARM_DESC(osd_yres,
0098 "Display height\n"
0099 "\t\t\tdefault 480 (PAL)\n"
0100 "\t\t\t 400 (NTSC)");
0101
0102 MODULE_PARM_DESC(osd_xres,
0103 "Display width\n"
0104 "\t\t\tdefault 640");
0105
0106 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
0107 MODULE_LICENSE("GPL");
0108
0109
0110
0111 #define IVTVFB_DBGFLG_WARN (1 << 0)
0112 #define IVTVFB_DBGFLG_INFO (1 << 1)
0113
0114 #define IVTVFB_DEBUG(x, type, fmt, args...) \
0115 do { \
0116 if ((x) & ivtvfb_debug) \
0117 printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
0118 } while (0)
0119 #define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
0120 #define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
0121
0122
0123 #define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->instance , ## args)
0124 #define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->instance , ## args)
0125 #define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
0126
0127
0128
0129 #define IVTV_OSD_MAX_WIDTH 720
0130 #define IVTV_OSD_MAX_HEIGHT 576
0131
0132 #define IVTV_OSD_BPP_8 0x00
0133 #define IVTV_OSD_BPP_16_444 0x03
0134 #define IVTV_OSD_BPP_16_555 0x02
0135 #define IVTV_OSD_BPP_16_565 0x01
0136 #define IVTV_OSD_BPP_32 0x04
0137
0138 struct osd_info {
0139
0140 unsigned long video_pbase;
0141
0142 u32 video_rbase;
0143
0144 volatile char __iomem *video_vbase;
0145
0146 u32 video_buffer_size;
0147
0148
0149 unsigned long fb_start_aligned_physaddr;
0150
0151 unsigned long fb_end_aligned_physaddr;
0152 int wc_cookie;
0153
0154
0155 int set_osd_coords_x;
0156 int set_osd_coords_y;
0157
0158
0159 int display_width;
0160 int display_height;
0161 int display_byte_stride;
0162
0163
0164 int bits_per_pixel;
0165 int bytes_per_pixel;
0166
0167
0168 struct fb_info ivtvfb_info;
0169 struct fb_var_screeninfo ivtvfb_defined;
0170 struct fb_fix_screeninfo ivtvfb_fix;
0171
0172
0173 struct fb_var_screeninfo fbvar_cur;
0174 int blank_cur;
0175 u32 palette_cur[256];
0176 u32 pan_cur;
0177 };
0178
0179 struct ivtv_osd_coords {
0180 unsigned long offset;
0181 unsigned long max_offset;
0182 int pixel_stride;
0183 int lines;
0184 int x;
0185 int y;
0186 };
0187
0188
0189
0190
0191
0192 static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
0193 u32 *fblength)
0194 {
0195 u32 data[CX2341X_MBOX_MAX_DATA];
0196 int rc;
0197
0198 ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
0199 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
0200 *fbbase = data[0];
0201 *fblength = data[1];
0202 return rc;
0203 }
0204
0205 static int ivtvfb_get_osd_coords(struct ivtv *itv,
0206 struct ivtv_osd_coords *osd)
0207 {
0208 struct osd_info *oi = itv->osd_info;
0209 u32 data[CX2341X_MBOX_MAX_DATA];
0210
0211 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
0212
0213 osd->offset = data[0] - oi->video_rbase;
0214 osd->max_offset = oi->display_width * oi->display_height * 4;
0215 osd->pixel_stride = data[1];
0216 osd->lines = data[2];
0217 osd->x = data[3];
0218 osd->y = data[4];
0219 return 0;
0220 }
0221
0222 static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
0223 {
0224 struct osd_info *oi = itv->osd_info;
0225
0226 oi->display_width = osd->pixel_stride;
0227 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
0228 oi->set_osd_coords_x += osd->x;
0229 oi->set_osd_coords_y = osd->y;
0230
0231 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
0232 osd->offset + oi->video_rbase,
0233 osd->pixel_stride,
0234 osd->lines, osd->x, osd->y);
0235 }
0236
0237 static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
0238 {
0239 int osd_height_limit = itv->is_out_50hz ? 576 : 480;
0240
0241
0242 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
0243 return -EINVAL;
0244
0245
0246 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
0247 IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
0248 ivtv_window->top, ivtv_window->height);
0249 ivtv_window->top = osd_height_limit - ivtv_window->height;
0250 }
0251
0252 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
0253 IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
0254 ivtv_window->left, ivtv_window->width);
0255 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
0256 }
0257
0258
0259 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
0260
0261
0262 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
0263
0264
0265 itv->yuv_info.osd_vis_w = ivtv_window->width;
0266 itv->yuv_info.osd_vis_h = ivtv_window->height;
0267 itv->yuv_info.osd_x_offset = ivtv_window->left;
0268 itv->yuv_info.osd_y_offset = ivtv_window->top;
0269
0270 return 0;
0271 }
0272
0273 static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
0274 unsigned long ivtv_dest_addr, void __user *userbuf,
0275 int size_in_bytes)
0276 {
0277 DEFINE_WAIT(wait);
0278 int got_sig = 0;
0279
0280 mutex_lock(&itv->udma.lock);
0281
0282 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
0283 mutex_unlock(&itv->udma.lock);
0284 IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, Error with pin_user_pages: %d bytes, %d pages returned\n",
0285 size_in_bytes, itv->udma.page_count);
0286
0287
0288 return -EIO;
0289 }
0290
0291 IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
0292 size_in_bytes, itv->udma.page_count);
0293
0294 ivtv_udma_prepare(itv);
0295 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
0296
0297
0298 while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
0299 test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
0300
0301
0302 got_sig = signal_pending(current);
0303 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
0304 break;
0305 got_sig = 0;
0306 schedule();
0307 }
0308 finish_wait(&itv->dma_waitq, &wait);
0309
0310
0311 ivtv_udma_unmap(itv);
0312 mutex_unlock(&itv->udma.lock);
0313 if (got_sig) {
0314 IVTV_DEBUG_INFO("User stopped OSD\n");
0315 return -EINTR;
0316 }
0317
0318 return 0;
0319 }
0320
0321 static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
0322 unsigned long dest_offset, int count)
0323 {
0324 DEFINE_WAIT(wait);
0325 struct osd_info *oi = itv->osd_info;
0326
0327
0328 if (count == 0) {
0329 IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
0330 return -EINVAL;
0331 }
0332
0333
0334 if ((dest_offset + count) > oi->video_buffer_size) {
0335 IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
0336 dest_offset + count, oi->video_buffer_size);
0337 return -E2BIG;
0338 }
0339
0340
0341 if ((unsigned long)source & 3)
0342 IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (%p)\n",
0343 source);
0344
0345 if (dest_offset & 3)
0346 IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
0347
0348 if (count & 3)
0349 IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
0350
0351
0352 if (!access_ok(source + dest_offset, count)) {
0353 IVTVFB_WARN("Invalid userspace pointer %p\n", source);
0354
0355 IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source %p count %d\n",
0356 dest_offset, source, count);
0357 return -EINVAL;
0358 }
0359
0360
0361 dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
0362
0363
0364 return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
0365 }
0366
0367 static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
0368 size_t count, loff_t *ppos)
0369 {
0370 unsigned long p = *ppos;
0371 void *dst;
0372 int err = 0;
0373 int dma_err;
0374 unsigned long total_size;
0375 struct ivtv *itv = (struct ivtv *) info->par;
0376 unsigned long dma_offset =
0377 IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
0378 unsigned long dma_size;
0379 u16 lead = 0, tail = 0;
0380
0381 if (info->state != FBINFO_STATE_RUNNING)
0382 return -EPERM;
0383
0384 total_size = info->screen_size;
0385
0386 if (total_size == 0)
0387 total_size = info->fix.smem_len;
0388
0389 if (p > total_size)
0390 return -EFBIG;
0391
0392 if (count > total_size) {
0393 err = -EFBIG;
0394 count = total_size;
0395 }
0396
0397 if (count + p > total_size) {
0398 if (!err)
0399 err = -ENOSPC;
0400 count = total_size - p;
0401 }
0402
0403 dst = (void __force *) (info->screen_base + p);
0404
0405 if (info->fbops->fb_sync)
0406 info->fbops->fb_sync(info);
0407
0408
0409
0410 if (count >= 4096 &&
0411 ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
0412
0413 if ((unsigned long)dst & 3) {
0414 lead = 4 - ((unsigned long)dst & 3);
0415 if (copy_from_user(dst, buf, lead))
0416 return -EFAULT;
0417 buf += lead;
0418 dst += lead;
0419 }
0420
0421 if ((count - lead) & 3)
0422 tail = (count - lead) & 3;
0423
0424 dma_size = count - lead - tail;
0425 dma_err = ivtvfb_prep_dec_dma_to_device(itv,
0426 p + lead + dma_offset, (void __user *)buf, dma_size);
0427 if (dma_err)
0428 return dma_err;
0429 dst += dma_size;
0430 buf += dma_size;
0431
0432 if (tail && copy_from_user(dst, buf, tail))
0433 return -EFAULT;
0434 } else if (copy_from_user(dst, buf, count)) {
0435 return -EFAULT;
0436 }
0437
0438 if (!err)
0439 *ppos += count;
0440
0441 return (err) ? err : count;
0442 }
0443
0444 static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
0445 {
0446 DEFINE_WAIT(wait);
0447 struct ivtv *itv = (struct ivtv *)info->par;
0448 int rc = 0;
0449
0450 switch (cmd) {
0451 case FBIOGET_VBLANK: {
0452 struct fb_vblank vblank;
0453 u32 trace;
0454
0455 memset(&vblank, 0, sizeof(struct fb_vblank));
0456
0457 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
0458 FB_VBLANK_HAVE_VSYNC;
0459 trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
0460 if (itv->is_out_50hz && trace > 312)
0461 trace -= 312;
0462 else if (itv->is_out_60hz && trace > 262)
0463 trace -= 262;
0464 if (trace == 1)
0465 vblank.flags |= FB_VBLANK_VSYNCING;
0466 vblank.count = itv->last_vsync_field;
0467 vblank.vcount = trace;
0468 vblank.hcount = 0;
0469 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
0470 return -EFAULT;
0471 return 0;
0472 }
0473
0474 case FBIO_WAITFORVSYNC:
0475 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
0476 if (!schedule_timeout(msecs_to_jiffies(50)))
0477 rc = -ETIMEDOUT;
0478 finish_wait(&itv->vsync_waitq, &wait);
0479 return rc;
0480
0481 case IVTVFB_IOC_DMA_FRAME: {
0482 struct ivtvfb_dma_frame args;
0483
0484 IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
0485 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
0486 return -EFAULT;
0487
0488 return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
0489 }
0490
0491 default:
0492 IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
0493 return -EINVAL;
0494 }
0495 return 0;
0496 }
0497
0498
0499
0500 static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
0501 {
0502 struct osd_info *oi = itv->osd_info;
0503 struct ivtv_osd_coords ivtv_osd;
0504 struct v4l2_rect ivtv_window;
0505 int osd_mode = -1;
0506
0507 IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
0508
0509
0510 if (var->nonstd)
0511 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
0512 else
0513 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
0514
0515
0516 switch (var->bits_per_pixel) {
0517 case 8:
0518 osd_mode = IVTV_OSD_BPP_8;
0519 break;
0520 case 32:
0521 osd_mode = IVTV_OSD_BPP_32;
0522 break;
0523 case 16:
0524 switch (var->green.length) {
0525 case 4:
0526 osd_mode = IVTV_OSD_BPP_16_444;
0527 break;
0528 case 5:
0529 osd_mode = IVTV_OSD_BPP_16_555;
0530 break;
0531 case 6:
0532 osd_mode = IVTV_OSD_BPP_16_565;
0533 break;
0534 default:
0535 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
0536 }
0537 break;
0538 default:
0539 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
0540 }
0541
0542
0543
0544 if (osd_mode != -1) {
0545 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
0546 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
0547 }
0548
0549 oi->bits_per_pixel = var->bits_per_pixel;
0550 oi->bytes_per_pixel = var->bits_per_pixel / 8;
0551
0552
0553 switch (var->vmode & FB_VMODE_MASK) {
0554 case FB_VMODE_NONINTERLACED:
0555 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
0556 break;
0557 case FB_VMODE_INTERLACED:
0558 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
0559 break;
0560 default:
0561 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
0562 }
0563
0564
0565 ivtvfb_get_osd_coords(itv, &ivtv_osd);
0566
0567
0568 ivtv_osd.pixel_stride = var->xres_virtual;
0569 ivtv_osd.lines = var->yres_virtual;
0570 ivtv_osd.x = 0;
0571 ivtv_osd.y = 0;
0572 ivtvfb_set_osd_coords(itv, &ivtv_osd);
0573
0574
0575
0576 ivtv_window.width = var->xres;
0577 ivtv_window.height = var->yres;
0578
0579
0580 if (!var->upper_margin)
0581 var->upper_margin++;
0582 if (!var->left_margin)
0583 var->left_margin++;
0584 ivtv_window.top = var->upper_margin - 1;
0585 ivtv_window.left = var->left_margin - 1;
0586
0587 ivtvfb_set_display_window(itv, &ivtv_window);
0588
0589
0590 itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
0591 itv->yuv_info.osd_full_h = ivtv_osd.lines;
0592
0593
0594 itv->yuv_info.yuv_forced_update = 1;
0595
0596
0597 memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
0598
0599 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
0600 var->xres, var->yres,
0601 var->xres_virtual, var->yres_virtual,
0602 var->bits_per_pixel);
0603
0604 IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
0605 var->left_margin, var->upper_margin);
0606
0607 IVTVFB_DEBUG_INFO("Display filter: %s\n",
0608 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
0609 IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
0610
0611 return 0;
0612 }
0613
0614 static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
0615 {
0616 struct osd_info *oi = itv->osd_info;
0617
0618 IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
0619 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
0620 strscpy(fix->id, "cx23415 TV out", sizeof(fix->id));
0621 fix->smem_start = oi->video_pbase;
0622 fix->smem_len = oi->video_buffer_size;
0623 fix->type = FB_TYPE_PACKED_PIXELS;
0624 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
0625 fix->xpanstep = 1;
0626 fix->ypanstep = 1;
0627 fix->ywrapstep = 0;
0628 fix->line_length = oi->display_byte_stride;
0629 fix->accel = FB_ACCEL_NONE;
0630 return 0;
0631 }
0632
0633
0634
0635
0636 static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
0637 {
0638 struct osd_info *oi = itv->osd_info;
0639 int osd_height_limit;
0640 u32 pixclock, hlimit, vlimit;
0641
0642 IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
0643
0644
0645 if (itv->is_out_50hz) {
0646 pixclock = 84316;
0647 hlimit = 776;
0648 vlimit = 591;
0649 osd_height_limit = 576;
0650 }
0651 else {
0652 pixclock = 83926;
0653 hlimit = 776;
0654 vlimit = 495;
0655 osd_height_limit = 480;
0656 }
0657
0658 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
0659 var->transp.offset = 24;
0660 var->transp.length = 8;
0661 var->red.offset = 16;
0662 var->red.length = 8;
0663 var->green.offset = 8;
0664 var->green.length = 8;
0665 var->blue.offset = 0;
0666 var->blue.length = 8;
0667 }
0668 else if (var->bits_per_pixel == 16) {
0669
0670 switch (var->green.length) {
0671 case 4:
0672 var->red.offset = 8;
0673 var->red.length = 4;
0674 var->green.offset = 4;
0675 var->green.length = 4;
0676 var->blue.offset = 0;
0677 var->blue.length = 4;
0678 var->transp.offset = 12;
0679 var->transp.length = 1;
0680 break;
0681 case 5:
0682 var->red.offset = 10;
0683 var->red.length = 5;
0684 var->green.offset = 5;
0685 var->green.length = 5;
0686 var->blue.offset = 0;
0687 var->blue.length = 5;
0688 var->transp.offset = 15;
0689 var->transp.length = 1;
0690 break;
0691 default:
0692 var->red.offset = 11;
0693 var->red.length = 5;
0694 var->green.offset = 5;
0695 var->green.length = 6;
0696 var->blue.offset = 0;
0697 var->blue.length = 5;
0698 var->transp.offset = 0;
0699 var->transp.length = 0;
0700 break;
0701 }
0702 }
0703 else {
0704 IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
0705 return -EINVAL;
0706 }
0707
0708
0709 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
0710 IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
0711 var->xres, var->yres);
0712 return -EINVAL;
0713 }
0714
0715
0716 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
0717 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
0718 var->xres_virtual < var->xres ||
0719 var->yres_virtual < var->yres) {
0720 IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
0721 var->xres_virtual, var->yres_virtual);
0722 return -EINVAL;
0723 }
0724
0725
0726 if (var->bits_per_pixel == 8) {
0727
0728 if (var->xres & 3) {
0729 IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
0730 return -EINVAL;
0731 }
0732 if (var->xres_virtual & 3) {
0733 IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
0734 return -EINVAL;
0735 }
0736 }
0737 else if (var->bits_per_pixel == 16) {
0738
0739 if (var->xres & 1) {
0740 IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
0741 return -EINVAL;
0742 }
0743 if (var->xres_virtual & 1) {
0744 IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
0745 return -EINVAL;
0746 }
0747 }
0748
0749
0750 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
0751 IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
0752 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
0753 return -EINVAL;
0754 }
0755
0756
0757 if (var->nonstd > 1) {
0758 IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
0759 return -EINVAL;
0760 }
0761
0762
0763 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
0764 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
0765 IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
0766 return -EINVAL;
0767 }
0768
0769
0770
0771
0772
0773 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1)
0774 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
0775
0776 if (var->upper_margin + var->yres > (itv->is_out_50hz ? 577 : 481))
0777 var->upper_margin = 1 + (((itv->is_out_50hz ? 576 : 480) -
0778 var->yres) / 2);
0779
0780
0781 var->right_margin = hlimit - var->left_margin - var->xres;
0782 var->lower_margin = vlimit - var->upper_margin - var->yres;
0783
0784
0785 var->hsync_len = 24;
0786 var->vsync_len = 2;
0787
0788
0789
0790
0791 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
0792 var->pixclock = pixclock / 2;
0793 else
0794 var->pixclock = pixclock;
0795
0796 itv->osd_rect.width = var->xres;
0797 itv->osd_rect.height = var->yres;
0798
0799 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
0800 var->xres, var->yres,
0801 var->xres_virtual, var->yres_virtual,
0802 var->bits_per_pixel);
0803
0804 IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
0805 var->left_margin, var->upper_margin);
0806
0807 IVTVFB_DEBUG_INFO("Display filter: %s\n",
0808 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
0809 IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
0810 return 0;
0811 }
0812
0813 static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
0814 {
0815 struct ivtv *itv = (struct ivtv *) info->par;
0816 IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
0817 return _ivtvfb_check_var(var, itv);
0818 }
0819
0820 static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
0821 {
0822 u32 osd_pan_index;
0823 struct ivtv *itv = (struct ivtv *) info->par;
0824
0825 if (var->yoffset + info->var.yres > info->var.yres_virtual ||
0826 var->xoffset + info->var.xres > info->var.xres_virtual)
0827 return -EINVAL;
0828
0829 osd_pan_index = var->yoffset * info->fix.line_length
0830 + var->xoffset * info->var.bits_per_pixel / 8;
0831 write_reg(osd_pan_index, 0x02A0C);
0832
0833
0834 itv->yuv_info.osd_x_pan = var->xoffset;
0835 itv->yuv_info.osd_y_pan = var->yoffset;
0836
0837 itv->yuv_info.yuv_forced_update = 1;
0838
0839 itv->osd_info->pan_cur = osd_pan_index;
0840 return 0;
0841 }
0842
0843 static int ivtvfb_set_par(struct fb_info *info)
0844 {
0845 int rc = 0;
0846 struct ivtv *itv = (struct ivtv *) info->par;
0847
0848 IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
0849
0850 rc = ivtvfb_set_var(itv, &info->var);
0851 ivtvfb_pan_display(&info->var, info);
0852 ivtvfb_get_fix(itv, &info->fix);
0853 ivtv_firmware_check(itv, "ivtvfb_set_par");
0854 return rc;
0855 }
0856
0857 static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
0858 unsigned blue, unsigned transp,
0859 struct fb_info *info)
0860 {
0861 u32 color, *palette;
0862 struct ivtv *itv = (struct ivtv *)info->par;
0863
0864 if (regno >= info->cmap.len)
0865 return -EINVAL;
0866
0867 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
0868 if (info->var.bits_per_pixel <= 8) {
0869 write_reg(regno, 0x02a30);
0870 write_reg(color, 0x02a34);
0871 itv->osd_info->palette_cur[regno] = color;
0872 return 0;
0873 }
0874 if (regno >= 16)
0875 return -EINVAL;
0876
0877 palette = info->pseudo_palette;
0878 if (info->var.bits_per_pixel == 16) {
0879 switch (info->var.green.length) {
0880 case 4:
0881 color = ((red & 0xf000) >> 4) |
0882 ((green & 0xf000) >> 8) |
0883 ((blue & 0xf000) >> 12);
0884 break;
0885 case 5:
0886 color = ((red & 0xf800) >> 1) |
0887 ((green & 0xf800) >> 6) |
0888 ((blue & 0xf800) >> 11);
0889 break;
0890 case 6:
0891 color = (red & 0xf800 ) |
0892 ((green & 0xfc00) >> 5) |
0893 ((blue & 0xf800) >> 11);
0894 break;
0895 }
0896 }
0897 palette[regno] = color;
0898 return 0;
0899 }
0900
0901
0902
0903 static int ivtvfb_blank(int blank_mode, struct fb_info *info)
0904 {
0905 struct ivtv *itv = (struct ivtv *)info->par;
0906
0907 IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
0908 switch (blank_mode) {
0909 case FB_BLANK_UNBLANK:
0910 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
0911 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
0912 break;
0913 case FB_BLANK_NORMAL:
0914 case FB_BLANK_HSYNC_SUSPEND:
0915 case FB_BLANK_VSYNC_SUSPEND:
0916 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
0917 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
0918 break;
0919 case FB_BLANK_POWERDOWN:
0920 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
0921 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
0922 break;
0923 }
0924 itv->osd_info->blank_cur = blank_mode;
0925 return 0;
0926 }
0927
0928 static const struct fb_ops ivtvfb_ops = {
0929 .owner = THIS_MODULE,
0930 .fb_write = ivtvfb_write,
0931 .fb_check_var = ivtvfb_check_var,
0932 .fb_set_par = ivtvfb_set_par,
0933 .fb_setcolreg = ivtvfb_setcolreg,
0934 .fb_fillrect = cfb_fillrect,
0935 .fb_copyarea = cfb_copyarea,
0936 .fb_imageblit = cfb_imageblit,
0937 .fb_cursor = NULL,
0938 .fb_ioctl = ivtvfb_ioctl,
0939 .fb_pan_display = ivtvfb_pan_display,
0940 .fb_blank = ivtvfb_blank,
0941 };
0942
0943
0944 static void ivtvfb_restore(struct ivtv *itv)
0945 {
0946 struct osd_info *oi = itv->osd_info;
0947 int i;
0948
0949 ivtvfb_set_var(itv, &oi->fbvar_cur);
0950 ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
0951 for (i = 0; i < 256; i++) {
0952 write_reg(i, 0x02a30);
0953 write_reg(oi->palette_cur[i], 0x02a34);
0954 }
0955 write_reg(oi->pan_cur, 0x02a0c);
0956 }
0957
0958
0959
0960
0961
0962 static int ivtvfb_init_vidmode(struct ivtv *itv)
0963 {
0964 struct osd_info *oi = itv->osd_info;
0965 struct v4l2_rect start_window;
0966 int max_height;
0967
0968
0969
0970 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
0971 osd_depth = 8;
0972 oi->bits_per_pixel = osd_depth;
0973 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
0974
0975
0976
0977 if (osd_xres > 720)
0978 osd_xres = 720;
0979
0980
0981 if (osd_depth == 8)
0982 osd_xres &= ~3;
0983 else if (osd_depth == 16)
0984 osd_xres &= ~1;
0985
0986 start_window.width = osd_xres ? osd_xres : 640;
0987
0988
0989 if (osd_left && osd_left + start_window.width > 721) {
0990 IVTVFB_ERR("Invalid osd_left - assuming default\n");
0991 osd_left = 0;
0992 }
0993
0994
0995 osd_left--;
0996
0997 start_window.left = osd_left >= 0 ?
0998 osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
0999
1000 oi->display_byte_stride =
1001 start_window.width * oi->bytes_per_pixel;
1002
1003
1004
1005 max_height = itv->is_out_50hz ? 576 : 480;
1006
1007 if (osd_yres > max_height)
1008 osd_yres = max_height;
1009
1010 start_window.height = osd_yres ?
1011 osd_yres : itv->is_out_50hz ? 480 : 400;
1012
1013
1014 if (osd_upper + start_window.height > max_height + 1) {
1015 IVTVFB_ERR("Invalid osd_upper - assuming default\n");
1016 osd_upper = 0;
1017 }
1018
1019
1020 osd_upper--;
1021
1022 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
1023
1024 oi->display_width = start_window.width;
1025 oi->display_height = start_window.height;
1026
1027
1028
1029 oi->ivtvfb_defined.xres = oi->display_width;
1030 oi->ivtvfb_defined.yres = oi->display_height;
1031 oi->ivtvfb_defined.xres_virtual = oi->display_width;
1032 oi->ivtvfb_defined.yres_virtual = oi->display_height;
1033 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
1034 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
1035 oi->ivtvfb_defined.left_margin = start_window.left + 1;
1036 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
1037 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
1038 oi->ivtvfb_defined.nonstd = 0;
1039
1040
1041
1042 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
1043
1044
1045
1046 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
1047
1048
1049
1050 oi->ivtvfb_info.node = -1;
1051 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
1052 oi->ivtvfb_info.par = itv;
1053 oi->ivtvfb_info.var = oi->ivtvfb_defined;
1054 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
1055 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
1056 oi->ivtvfb_info.fbops = &ivtvfb_ops;
1057
1058
1059 oi->ivtvfb_info.monspecs.hfmin = 8000;
1060 oi->ivtvfb_info.monspecs.hfmax = 70000;
1061 oi->ivtvfb_info.monspecs.vfmin = 10;
1062 oi->ivtvfb_info.monspecs.vfmax = 100;
1063
1064
1065 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
1066 IVTVFB_ERR("abort, unable to alloc cmap\n");
1067 return -ENOMEM;
1068 }
1069
1070
1071 oi->ivtvfb_info.pseudo_palette =
1072 kmalloc_array(16, sizeof(u32), GFP_KERNEL|__GFP_NOWARN);
1073
1074 if (!oi->ivtvfb_info.pseudo_palette) {
1075 IVTVFB_ERR("abort, unable to alloc pseudo palette\n");
1076 return -ENOMEM;
1077 }
1078
1079 return 0;
1080 }
1081
1082
1083
1084 static int ivtvfb_init_io(struct ivtv *itv)
1085 {
1086 struct osd_info *oi = itv->osd_info;
1087
1088 int size_shift = 31;
1089
1090 mutex_lock(&itv->serialize_lock);
1091 if (ivtv_init_on_first_open(itv)) {
1092 mutex_unlock(&itv->serialize_lock);
1093 IVTVFB_ERR("Failed to initialize ivtv\n");
1094 return -ENXIO;
1095 }
1096 mutex_unlock(&itv->serialize_lock);
1097
1098 if (ivtvfb_get_framebuffer(itv, &oi->video_rbase,
1099 &oi->video_buffer_size) < 0) {
1100 IVTVFB_ERR("Firmware failed to respond\n");
1101 return -EIO;
1102 }
1103
1104
1105
1106
1107 oi->video_buffer_size = 1704960;
1108
1109 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1110 oi->video_vbase = itv->dec_mem + oi->video_rbase;
1111
1112 if (!oi->video_vbase) {
1113 IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1114 oi->video_buffer_size, oi->video_pbase);
1115 return -EIO;
1116 }
1117
1118 IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1119 oi->video_pbase, oi->video_vbase,
1120 oi->video_buffer_size / 1024);
1121
1122 while (!(oi->video_buffer_size & (1 << size_shift)))
1123 size_shift--;
1124 size_shift++;
1125 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1126 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1127 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1128 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1129 oi->wc_cookie = arch_phys_wc_add(oi->fb_start_aligned_physaddr,
1130 oi->fb_end_aligned_physaddr -
1131 oi->fb_start_aligned_physaddr);
1132
1133 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
1134
1135 return 0;
1136 }
1137
1138
1139 static void ivtvfb_release_buffers (struct ivtv *itv)
1140 {
1141 struct osd_info *oi = itv->osd_info;
1142
1143
1144 if (oi->ivtvfb_info.cmap.len)
1145 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
1146
1147
1148 kfree(oi->ivtvfb_info.pseudo_palette);
1149 arch_phys_wc_del(oi->wc_cookie);
1150 kfree(oi);
1151 itv->osd_info = NULL;
1152 }
1153
1154
1155
1156 static int ivtvfb_init_card(struct ivtv *itv)
1157 {
1158 int rc;
1159
1160 #if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
1161 if (pat_enabled()) {
1162 if (ivtvfb_force_pat) {
1163 pr_info("PAT is enabled. Write-combined framebuffer caching will be disabled.\n");
1164 pr_info("To enable caching, boot with nopat kernel parameter\n");
1165 } else {
1166 pr_warn("ivtvfb needs PAT disabled for write-combined framebuffer caching.\n");
1167 pr_warn("Boot with nopat kernel parameter to use caching, or use the\n");
1168 pr_warn("force_pat module parameter to run with caching disabled\n");
1169 return -ENODEV;
1170 }
1171 }
1172 #endif
1173
1174 if (itv->osd_info) {
1175 IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
1176 return -EBUSY;
1177 }
1178
1179 itv->osd_info = kzalloc(sizeof(struct osd_info),
1180 GFP_KERNEL|__GFP_NOWARN);
1181 if (itv->osd_info == NULL) {
1182 IVTVFB_ERR("Failed to allocate memory for osd_info\n");
1183 return -ENOMEM;
1184 }
1185
1186
1187 rc = ivtvfb_init_io(itv);
1188 if (rc) {
1189 ivtvfb_release_buffers(itv);
1190 return rc;
1191 }
1192
1193
1194 if ((rc = ivtvfb_init_vidmode(itv))) {
1195 ivtvfb_release_buffers(itv);
1196 return rc;
1197 }
1198
1199
1200 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1201 ivtvfb_release_buffers(itv);
1202 return -EINVAL;
1203 }
1204
1205 itv->osd_video_pbase = itv->osd_info->video_pbase;
1206
1207
1208 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1209
1210
1211 write_reg(0, 0x02a30);
1212 write_reg(0, 0x02a34);
1213
1214
1215 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1216
1217
1218 itv->ivtvfb_restore = ivtvfb_restore;
1219
1220
1221 ivtv_udma_alloc(itv);
1222 itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |=
1223 V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
1224 itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |=
1225 V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
1226 itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
1227 return 0;
1228
1229 }
1230
1231 static int __init ivtvfb_callback_init(struct device *dev, void *p)
1232 {
1233 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
1234 struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
1235
1236 if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
1237 if (ivtvfb_init_card(itv) == 0) {
1238 IVTVFB_INFO("Framebuffer registered on %s\n",
1239 itv->v4l2_dev.name);
1240 (*(int *)p)++;
1241 }
1242 }
1243 return 0;
1244 }
1245
1246 static int ivtvfb_callback_cleanup(struct device *dev, void *p)
1247 {
1248 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
1249 struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
1250 struct osd_info *oi = itv->osd_info;
1251
1252 if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
1253 itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps &=
1254 ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
1255 itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps &=
1256 ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
1257 itv->v4l2_cap &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
1258 unregister_framebuffer(&itv->osd_info->ivtvfb_info);
1259 IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
1260 itv->ivtvfb_restore = NULL;
1261 ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
1262 ivtvfb_release_buffers(itv);
1263 itv->osd_video_pbase = 0;
1264 }
1265 return 0;
1266 }
1267
1268 static int __init ivtvfb_init(void)
1269 {
1270 struct device_driver *drv;
1271 int registered = 0;
1272 int err;
1273
1274
1275 if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
1276 pr_err("ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
1277 IVTV_MAX_CARDS - 1);
1278 return -EINVAL;
1279 }
1280
1281 drv = driver_find("ivtv", &pci_bus_type);
1282 err = driver_for_each_device(drv, NULL, ®istered, ivtvfb_callback_init);
1283 (void)err;
1284 if (!registered) {
1285 pr_err("no cards found\n");
1286 return -ENODEV;
1287 }
1288 return 0;
1289 }
1290
1291 static void ivtvfb_cleanup(void)
1292 {
1293 struct device_driver *drv;
1294 int err;
1295
1296 pr_info("Unloading framebuffer module\n");
1297
1298 drv = driver_find("ivtv", &pci_bus_type);
1299 err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
1300 (void)err;
1301 }
1302
1303 module_init(ivtvfb_init);
1304 module_exit(ivtvfb_cleanup);