Index: vidix/ivtv_vid.c =================================================================== --- vidix/ivtv_vid.c (Revision 27281) +++ vidix/ivtv_vid.c (Arbeitskopie) @@ -21,7 +21,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include +#include #include #include #include @@ -30,6 +32,7 @@ #include #include #include +#include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) @@ -223,14 +226,30 @@ int ivtv_probe(int verbose,int force __attribute__ ((unused))) { - unsigned char fb_number = 0; - char *device_name = NULL; char *alpha = NULL; + char *ivtv_video_device_name = NULL; + char *ivtv_framebuffer_device_name = NULL; struct fb_var_screeninfo vinfo; - char fb_dev_name[] = "/dev/fb0\0"; pciinfo_t lst[MAX_PCI_DEVICES]; int err = 0; unsigned int i, num_pci = 0; + struct stat fileStat; + char sysfsVideoClass[] = "/sys/class/video4linux\0"; + char sysfsGraphicsClass[] = "/sys/class/graphics\0"; + char *yuv_searchPattern[] = { "/sys/class/video4linux/video*\0", "/dev/video*\0"}; + char *fb_searchPattern[] = { "/sys/class/graphics/fb*\0", "/dev/fb*\0"}; + int yuv_patNr = 0; + int fb_patNr = 0; + glob_t searchResult; + char deviceName[] = "/dev/videoXXXXX\0"; + int devLen = 0; + struct v4l2_capability vcap; + struct v4l2_fmtdesc vfdesc; + int found_yuv_format = 0; + char *tmpStr = NULL; + int yuvDevNumber = -1; + struct v4l2_framebuffer fbuf; + struct fb_fix_screeninfo fbsi; if(verbose) printf(IVTV_MSG"probe\n"); @@ -270,62 +289,187 @@ card_found: - device_name = getenv("FRAMEBUFFER"); - if(NULL == device_name) { - device_name = fb_dev_name; + if((NULL != (ivtv_video_device_name = getenv("VIDIXIVTVVIDEODEV"))) && (NULL != (ivtv_framebuffer_device_name = getenv("VIDIXIVTVFRAMEBUFFERDEV")))) { + yuvdev = open(ivtv_video_device_name, O_RDWR); + if(-1 != yuvdev) { + fbdev = open(ivtv_framebuffer_device_name, O_RDWR); + if(-1 == fbdev) { + close(yuvdev); + yuvdev = -1; + } else + goto yuv_found; + } } + + /* test if sysfs is present, otherwise fallback to /dev */ + if(access(sysfsVideoClass, F_OK) < 0) + yuv_patNr = 1; + if(access(sysfsGraphicsClass, F_OK) < 0) + fb_patNr = 1; - fb_number = atoi(device_name+strlen("/dev/fb")); + /* search for the installed video devices */ + if(glob(yuv_searchPattern[yuv_patNr], GLOB_MARK, 0, &searchResult) == 0) { + for(i = 0; (yuvDevNumber < 0) && (i < searchResult.gl_pathc); i++) { + if(stat(searchResult.gl_pathv[i], &fileStat) == 0) { + devLen = 0; + if((yuv_patNr == 0) && S_ISDIR(fileStat.st_mode)) { + /* get the related device-node */ + snprintf(deviceName, sizeof(deviceName), "/dev/%s", searchResult.gl_pathv[i] + strlen(sysfsVideoClass) + 1); + devLen = strlen(deviceName); + if(deviceName[devLen - 1] == '/') { + devLen--; + deviceName[devLen]= 0; + } + } else if((yuv_patNr == 1) && !S_ISDIR(fileStat.st_mode)) { + snprintf(deviceName, sizeof(deviceName), "%s", searchResult.gl_pathv[i]); + devLen = strlen(deviceName); + } + + if(devLen > 0) { + yuvdev = open(deviceName, O_RDONLY); + if(-1 == yuvdev) { + printf(IVTV_MSG"Error occured during opening %s\n", deviceName); + } else { + if(ioctl(yuvdev, VIDIOC_QUERYCAP, &vcap) < 0) { + printf(IVTV_MSG"unable to query capabilites of %s\n", deviceName); + } else if(strncmp(vcap.driver, "ivtv", 4) == 0) { + if(vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT) { + /* it is a device handled by ivtv and it has an output */ + vfdesc.index = 0; + vfdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + found_yuv_format = 0; + while(ioctl(yuvdev, VIDIOC_ENUM_FMT, &vfdesc) == 0) { + if(vfdesc.pixelformat == V4L2_PIX_FMT_HM12) { + found_yuv_format= 1; + break; + } + vfdesc.index++; + } + if(found_yuv_format) { + /* it supports the needed pixel format */ - fbdev = open(device_name, O_RDWR); - if(-1 != fbdev) { - if(ioctl(fbdev, FBIOGET_VSCREENINFO, &vinfo) < 0) { - printf(IVTV_MSG"Unable to read screen info\n"); - close(fbdev); - return ENXIO; - } else { - fb_width = vinfo.xres; - fb_height = vinfo.yres; - if(2 == ivtv_verbose) { - printf(IVTV_MSG"framebuffer width : %3.0f\n",fb_width); - printf(IVTV_MSG"framebuffer height: %3.0f\n",fb_height); + /* hack is here + there is a problem at the v4l2-api + a PVR350 has multiple devices + /dev/video0 + /dev/video16 + /dev/video32 + /dev/video48 + VIDIOC_QUERYCAP returns the same for every device + so the code has to know that the YUV-decoder is + at /dev/video48 or higher + + maybe this is solved in the future... + */ + tmpStr = deviceName + devLen; + while((tmpStr >= deviceName) && isdigit((tmpStr-1)[0])) + tmpStr--; + if(tmpStr > deviceName) { + yuvDevNumber = atoi(tmpStr); + if(yuvDevNumber < 48) + yuvDevNumber = -1; + } + } + } + } + close(yuvdev); + yuvdev = -1; + } + } } } - if(NULL != (alpha = getenv("VIDIXIVTVALPHA"))) { - if(0 == strcmp(alpha, "disable")) { - alpha_disable = 1; - } - } - } else { - printf(IVTV_MSG"Failed to open /dev/fb%u\n", fb_number); + } + globfree(&searchResult); + if(yuvDevNumber < 0) { + printf(IVTV_MSG"no ivtv-driven yuv-decoder found\n"); + printf(IVTV_MSG"try to set VIDIXIVTVVIDEODEV and VIDIXIVTVFRAMEBUFFERDEV to the right devicenames (e.g. /dev/video48 and /dev/fb1)\n"); return ENXIO; } - /* Try to find YUV device */ - unsigned char yuv_device_number = 48, yuv_device = 48 + fb_number; - char yuv_device_name[] = "/dev/videoXXX\0"; - - do { - sprintf(yuv_device_name, "/dev/video%u", yuv_device); - yuvdev = open(yuv_device_name, O_RDWR); - if(-1 != yuvdev) { - if(ivtv_verbose) - printf(IVTV_MSG"YUV device found /dev/video%u\n", yuv_device); + snprintf(deviceName, sizeof(deviceName), "/dev/video%d", yuvDevNumber); + yuvdev = open(deviceName, O_RDWR); + if(-1 == yuvdev) { + printf(IVTV_MSG"Error opening yuv-decoder %s\n", deviceName); + } else { + if(verbose) + printf(IVTV_MSG"Found yuv-decoder %s\n", deviceName); + if(ioctl(yuvdev, VIDIOC_G_FBUF, &fbuf) == 0) { + /* searching for the related framebuffer-device */ + if(glob(fb_searchPattern[fb_patNr], GLOB_MARK, 0, &searchResult) == 0) { + for(i = 0; i < searchResult.gl_pathc; i++) { + if(stat(searchResult.gl_pathv[ i], &fileStat) == 0) { + devLen = 0; + if((fb_patNr == 0) && S_ISDIR(fileStat.st_mode)) { + snprintf(deviceName, sizeof(deviceName), "/dev/%s", searchResult.gl_pathv[i] + strlen(sysfsGraphicsClass) + 1); + devLen = strlen( deviceName); + if(deviceName[devLen - 1] == '/') { + devLen--; + deviceName[devLen] = 0; + } + } else if((fb_patNr == 1) && !S_ISDIR(fileStat.st_mode)) { + snprintf(deviceName, sizeof(deviceName), "%s", searchResult.gl_pathv[i]); + devLen = strlen(deviceName); + } + + if(devLen > 0) { + fbdev = open(deviceName, O_RDWR); + if(-1 == fbdev) { + printf(IVTV_MSG"Error occured during opening %s\n", deviceName); + } else { + if(0 == ioctl(fbdev, FBIOGET_FSCREENINFO, &fbsi)) { + if(fbsi.smem_start == (unsigned long) fbuf.base) + break; /* found it */ + } + close(fbdev); + fbdev = -1; + } + } + } + } + globfree(&searchResult); + } + } + if(-1 == fbdev) { + printf(IVTV_MSG"no related framebuffer found\n"); + printf(IVTV_MSG"try to set VIDIXIVTVVIDEODEV and VIDIXIVTVFRAMEBUFFERDEV to the right devicenames (e.g. /dev/video48 and /dev/fb1)\n"); + } else goto yuv_found; - } else { - if(ivtv_verbose) - printf(IVTV_MSG"YUV device not found: /dev/video%u\n", yuv_device); - } - } while(yuv_device-- > yuv_device_number); + } + close(yuvdev); + yuvdev = -1; return ENXIO; yuv_found: + + if(ioctl(fbdev, FBIOGET_VSCREENINFO, &vinfo) < 0) { + printf(IVTV_MSG"Unable to read screen info\n"); + close(fbdev); + fbdev = -1; + close(yuvdev); + yuvdev = -1; + return ENXIO; + } else { + fb_width = vinfo.xres; + fb_height = vinfo.yres; + if(2 == ivtv_verbose) { + printf(IVTV_MSG"framebuffer width : %3.0f\n",fb_width); + printf(IVTV_MSG"framebuffer height: %3.0f\n",fb_height); + } + } + if(NULL != (alpha = getenv("VIDIXIVTVALPHA"))) { + if(0 == strcmp(alpha, "disable")) { + alpha_disable = 1; + } + } + if(0 == alpha_disable) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) if(ioctl(fbdev, IVTVFB_IOCTL_GET_STATE, &fb_state_old) < 0) { printf(IVTV_MSG"Unable to read fb state\n"); close(yuvdev); + yuvdev = -1; close(fbdev); + fbdev = -1; return ENXIO; } else { if(ivtv_verbose) { @@ -341,7 +485,9 @@ if(ioctl(yuvdev, VIDIOC_G_FMT , &format_old) < 0) { printf(IVTV_MSG"Unable to read fb state\n"); close(yuvdev); + yuvdev = -1; close(fbdev); + fbdev = -1; return ENXIO; } else { if(ivtv_verbose) {