$OpenBSD: patch-vid_c,v 1.3 2003/01/20 18:54:14 sturm Exp $ --- vid.c.orig Mon May 8 06:59:03 2000 +++ vid.c Mon Jan 20 17:56:47 2003 @@ -48,15 +48,15 @@ ov511_reg_read(int fd, int reg) { struct usb_ctl_request ur; unsigned char data[1024]; - ur.request.bmRequestType = UT_READ_VENDOR_INTERFACE; - ur.request.bRequest = 2; + ur.ucr_request.bmRequestType = UT_READ_VENDOR_INTERFACE; + ur.ucr_request.bRequest = 2; - USETW(ur.request.wValue, 0); /* unused */ - USETW(ur.request.wIndex, reg); /* index */ - USETW(ur.request.wLength, 1); /* payload len in bytes */ - ur.data = data; - ur.flags = 0; - ur.actlen = 0; + USETW(ur.ucr_request.wValue, 0); /* unused */ + USETW(ur.ucr_request.wIndex, reg); /* index */ + USETW(ur.ucr_request.wLength, 1); /* payload len in bytes */ + ur.ucr_data = data; + ur.ucr_flags = 0; + ur.ucr_actlen = 0; if(ioctl(fd, USB_DO_REQUEST, &ur) < 0) { return -1; @@ -72,15 +72,15 @@ ov511_reg_write(int fd, int reg, int val data[0] = val; - ur.request.bmRequestType = UT_WRITE_VENDOR_INTERFACE; - ur.request.bRequest = 2; + ur.ucr_request.bmRequestType = UT_WRITE_VENDOR_INTERFACE; + ur.ucr_request.bRequest = 2; - USETW(ur.request.wValue, 0); /* unused */ - USETW(ur.request.wIndex, reg); /* index */ - USETW(ur.request.wLength, 1); /* payload len in bytes */ - ur.data = data; - ur.flags = 0; - ur.actlen = 0; + USETW(ur.ucr_request.wValue, 0); /* unused */ + USETW(ur.ucr_request.wIndex, reg); /* index */ + USETW(ur.ucr_request.wLength, 1); /* payload len in bytes */ + ur.ucr_data = data; + ur.ucr_flags = 0; + ur.ucr_actlen = 0; if(ioctl(fd, USB_DO_REQUEST, &ur) < 0) { return -1; @@ -213,16 +213,23 @@ main(int argc, char *argv[]) { char dev[FILENAME_MAX]; /* for constructing device names */ char isocdev[FILENAME_MAX]; /* for constructing endpoint 1 device names */ char *devname = NULL; /* device name */ + char *p = NULL; /* for string ops */ + int slen = -1; /* string length holder */ + int plen = -1; /* string length holder */ int len = -1; /* isochronous input read length */ struct vidstate vs; /* current read state */ int small = 0; /* use 320x240 */ int frmnm = 0; /* cyclic frame number key */ + int isplus; /* bridge is OV511+ if true, else OV511 */ + int is20; /* sensor is OV7620 if true, else OV7610 */ + int bufsize; /* size of packet buffer */ + /* pnm_init(&argc, argv); */ /* required for PNM programs? */ while(++argv, --argc) { if(strcmp(*argv, "--version") == 0) { - fprintf(stderr, "OV511 capture program version " VERSION + fprintf(stderr, "OV511/OV511+ capture program version " VERSION "\nCopyright 2000 Peter S. Housel" "\nThis program is free software; " "you may redistribute it under the terms of" @@ -235,7 +242,7 @@ main(int argc, char *argv[]) { exit(0); } else if(strcmp(*argv, "--help") == 0) { fprintf(stderr, "usage: vid [options]\n" - "Capture an image frame from an OV511-based USB video camera\n" + "Capture an image frame from an OV511/OV511+ based USB video camera\n" "and write image data to standard output in PNM format\n\n" "--version print program version information\n" "--usage summarize command line options\n" @@ -243,6 +250,7 @@ main(int argc, char *argv[]) { "--small capture as 320x240 image (default is 640x480)\n" "-d device, --device-name=device\n" " specify OV511 ugen device\n"); + fprintf(stderr, "example: vid | pnmtojpeg > ~/public_html/mywebcam.jpg\n"); exit(0); } else if(strcmp(*argv, "--small") == 0) { small = 1; @@ -287,18 +295,21 @@ main(int argc, char *argv[]) { exit(1); } - if(udi.vendorNo != 0x05A9 || udi.productNo != 0x0511) { - fprintf(stderr, "device %s is not an OmniVision OV511\n", devname); + if(udi.udi_vendorNo != 0x05A9 || + (udi.udi_productNo != 0x0511 && udi.udi_productNo != 0xa511)) { + fprintf(stderr, "device %s is not an OmniVision OV511/OV511+\n", devname); exit(1); } } else { int i = 0; for(i = 0; i < 15; ++i) { - sprintf(dev, "/dev/ugen%d", i); + snprintf(dev, sizeof(dev), "/dev/ugen%d.00", i); if((fd = open(dev, O_RDWR)) < 0) continue; - if(ioctl(fd, USB_GET_DEVICEINFO, &udi) < 0 - || udi.vendorNo != 0x05A9 || udi.productNo != 0x0511) { + if(ioctl(fd, USB_GET_DEVICEINFO, &udi) < 0 || + udi.udi_vendorNo != 0x05A9 || + (udi.udi_productNo != 0x0511 && + udi.udi_productNo != 0xa511)) { close(fd); fd = -1; continue; @@ -308,12 +319,15 @@ main(int argc, char *argv[]) { } if(fd < 0) { - fprintf(stderr, "vid: couldn't locate an OV511 device\n"); + fprintf(stderr, "vid: couldn't locate an OV511/OV511+ device\n"); exit(1); } devname = dev; } + + isplus = udi.udi_productNo == 0xa511; + bufsize = (isplus ? 961 : 993); /* reset the OV511 */ if(ov511_reg_write(fd, OV511_REG_RST, 0x7f) < 0) @@ -398,23 +412,56 @@ main(int argc, char *argv[]) { if(ov511_reg_write(fd, OV511_REG_CE_EN, 0x0) < 0) exit(1); - ov511_i2c_write(fd, OV7610_REG_RWB, 0x5); - ov511_i2c_write(fd, OV7610_REG_EC, 0xFF); - ov511_i2c_write(fd, OV7610_REG_COMB, 0x01); - ov511_i2c_write(fd, OV7610_REG_FD, 0x06); - ov511_i2c_write(fd, OV7610_REG_COME, 0x1c); - ov511_i2c_write(fd, OV7610_REG_COMF, 0x90); - ov511_i2c_write(fd, OV7610_REG_ECW, 0x2e); - ov511_i2c_write(fd, OV7610_REG_ECB, 0x7C); - ov511_i2c_write(fd, OV7610_REG_COMH, 0x24); - ov511_i2c_write(fd, OV7610_REG_EHSH, 0x04); - ov511_i2c_write(fd, OV7610_REG_EHSL, 0xAC); - ov511_i2c_write(fd, OV7610_REG_EXBK, 0xFE); - ov511_i2c_write(fd, OV7610_REG_COMJ, 0x93); - ov511_i2c_write(fd, OV7610_REG_BADJ, 0x48); - ov511_i2c_write(fd, OV7610_REG_COMK, 0x81); + /* This returns 0 if we have an OV7620 sensor */ + if((is20 = ov511_i2c_read(fd, OV7610_REG_COMI)) < 0) + exit(1); + is20 = !is20; + + /* set up the OV7610/OV7620 */ + if(is20) { + ov511_i2c_write(fd, OV7610_REG_EC, 0xff); + ov511_i2c_write(fd, OV7610_REG_FD, 0x06); + ov511_i2c_write(fd, OV7610_REG_COMH, 0x24); + ov511_i2c_write(fd, OV7610_REG_EHSL, 0xac); + ov511_i2c_write(fd, OV7610_REG_COMA, 0x00); + ov511_i2c_write(fd, OV7610_REG_COMH, 0x24); + ov511_i2c_write(fd, OV7610_REG_RWB, 0x85); + ov511_i2c_write(fd, OV7610_REG_COMD, 0x01); + ov511_i2c_write(fd, 0x23, 0x00); + ov511_i2c_write(fd, OV7610_REG_ECW, 0x10); + ov511_i2c_write(fd, OV7610_REG_ECB, 0x8a); + ov511_i2c_write(fd, OV7610_REG_COMG, 0xe2); + ov511_i2c_write(fd, OV7610_REG_EHSH, 0x00); + ov511_i2c_write(fd, OV7610_REG_EXBK, 0xfe); + ov511_i2c_write(fd, 0x30, 0x71); + ov511_i2c_write(fd, 0x31, 0x60); + ov511_i2c_write(fd, 0x32, 0x26); + ov511_i2c_write(fd, OV7610_REG_YGAM, 0x20); + ov511_i2c_write(fd, OV7610_REG_BADJ, 0x48); + ov511_i2c_write(fd, OV7610_REG_COMA, 0x24); + ov511_i2c_write(fd, OV7610_REG_SYN_CLK, 0x01); + ov511_i2c_write(fd, OV7610_REG_BBS, 0x24); + ov511_i2c_write(fd, OV7610_REG_RBS, 0x24); + } else { + ov511_i2c_write(fd, OV7610_REG_RWB, 0x5); + ov511_i2c_write(fd, OV7610_REG_EC, 0xFF); + ov511_i2c_write(fd, OV7610_REG_COMB, 0x01); + ov511_i2c_write(fd, OV7610_REG_FD, 0x06); + ov511_i2c_write(fd, OV7610_REG_COME, 0x1c); + ov511_i2c_write(fd, OV7610_REG_COMF, 0x90); + ov511_i2c_write(fd, OV7610_REG_ECW, 0x2e); + ov511_i2c_write(fd, OV7610_REG_ECB, 0x7C); + ov511_i2c_write(fd, OV7610_REG_COMH, 0x24); + ov511_i2c_write(fd, OV7610_REG_EHSH, 0x04); + ov511_i2c_write(fd, OV7610_REG_EHSL, 0xAC); + ov511_i2c_write(fd, OV7610_REG_EXBK, 0xFE); + ov511_i2c_write(fd, OV7610_REG_COMJ, 0x93); + ov511_i2c_write(fd, OV7610_REG_BADJ, 0x48); + ov511_i2c_write(fd, OV7610_REG_COMK, 0x81); + + ov511_i2c_write(fd, OV7610_REG_GAM, 0x04); + } - ov511_i2c_write(fd, OV7610_REG_GAM, 0x04); if(small) { vs.width = 320; @@ -442,14 +489,14 @@ main(int argc, char *argv[]) { ov511_reg_write(fd, OV511_REG_LNDV, 0x00); /* set FIFO format (993-byte packets) */ - if(ov511_reg_write(fd, OV511_REG_PKSZ, 0x1F) < 0) + if(ov511_reg_write(fd, OV511_REG_PKSZ, bufsize/32) < 0) exit(1); if(ov511_reg_write(fd, OV511_REG_PKFMT, 0x03) < 0) exit(1); /* select the 993-byte alternative */ - alt.interface_index = 0; - alt.alt_no = 1; + alt.uai_interface_index = 0; + alt.uai_alt_no = (isplus ? 7 : 1); if(ioctl(fd, USB_SET_ALTINTERFACE, &alt) < 0) { perror("USB_SET_ALTINTERFACE"); exit(1); @@ -468,43 +515,62 @@ main(int argc, char *argv[]) { vs.xels = pnm_allocarray(vs.width, vs.height); /* open the isochronous endpoint (endpoint 1) */ - sprintf(isocdev, "%s.1", devname); + /* first we need to construct the endpoint device from */ + /* the given device */ + p = strchr(devname, '.'); + slen = strlen(devname); + if(p == NULL) { + /* there is no dot, just append the isoc endpoint */ + /* this is horribly contrived and needs some work, */ + /* at this point OpenBSD doesn't use /dev/ugenX so */ + /* it will get fixed if soon */ + snprintf(isocdev, sizeof(isocdev), "%s.01", devname); + } else { + /* there is a dot */ + plen = strlen(p); + snprintf(isocdev, sizeof(isocdev), "%s", devname); + isocdev[slen - plen] = NULL; + snprintf(isocdev, sizeof(isocdev), "%s.01", isocdev); + } + if((isoc = open(isocdev, O_RDONLY)) < 0) { perror(isocdev); exit(1); } /* read, looking for start and end frames */ - while(vs.state != DONE && (len = read(isoc, &buf, 993)) >= 0) { + while(vs.state != DONE && (len = read(isoc, &buf, bufsize)) >= 0) { if(buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0 && buf[4] == 0 && buf[5] == 0 && buf[6] == 0 && buf[7] == 0 - && (buf[8] & 0x80) == 0 && buf[992] == 0 && vs.state == SKIPPING) { + && (buf[8] & 0x80) == 0 && buf[bufsize-1] == 0 && vs.state == SKIPPING) { vs.state = READING; vs.iY = vs.jY = vs.iUV = vs.jUV = 0; vs.residue = 0; - procdata(&vs, buf + 9, 993 - 10); + procdata(&vs, buf + 9, bufsize - 10); } else if(buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0 && buf[4] == 0 && buf[5] == 0 && buf[6] == 0 && buf[7] == 0 - && (buf[8] & 0x80) == 0x80 && buf[992] == 0 + && (buf[8] & 0x80) == 0x80 && buf[bufsize-1] == 0 && vs.state == READING) { vs.state = DONE; } else if(vs.state == READING) { - procdata(&vs, buf, 993 - 1); + procdata(&vs, buf, bufsize - 1); /* abort the capture and start over if packets come in out-of-order */ - if(buf[992] != frmnm && buf[992] != 1) { + if(buf[bufsize-1] != frmnm && buf[bufsize-1] != 1) { vs.state = SKIPPING; } - frmnm = buf[992] + 1; + frmnm = buf[bufsize-1] + 1; if(frmnm == 256) frmnm = 1; - } else if(buf[992] != 0) { - frmnm = buf[992] + 1; + } else if(buf[bufsize-1] != 0) { + frmnm = buf[bufsize-1] + 1; if(frmnm == 256) frmnm = 1; } } + /* reset and close the OV511 */ + ov511_reg_write(fd, OV511_REG_RST, 0x7f); close(isoc); close(fd);