📄 sunplus.c
字号:
/* write <len> bytes from gspca_dev->usb_buf */static void reg_w(struct gspca_dev *gspca_dev, __u16 req, __u16 value, __u16 index, __u16 len){#ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { err("reg_w: buffer overflow"); return; }#endif usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, len ? gspca_dev->usb_buf : NULL, len, 500);}/* write req / index / value */static int reg_w_riv(struct usb_device *dev, __u16 req, __u16 index, __u16 value){ int ret; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, NULL, 0, 500); PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", req, index, value, ret); if (ret < 0) PDEBUG(D_ERR, "reg write: error %d", ret); return ret;}/* read 1 byte */static int reg_r_1(struct gspca_dev *gspca_dev, __u16 value) /* wValue */{ int ret; ret = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), 0x20, /* request */ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, /* index */ gspca_dev->usb_buf, 1, 500); /* timeout */ if (ret < 0) { PDEBUG(D_ERR, "reg_r_1 err %d", ret); return 0; } return gspca_dev->usb_buf[0];}/* read 1 or 2 bytes - returns < 0 if error */static int reg_r_12(struct gspca_dev *gspca_dev, __u16 req, /* bRequest */ __u16 index, /* wIndex */ __u16 length) /* wLength (1 or 2 only) */{ int ret; gspca_dev->usb_buf[1] = 0; ret = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, /* value */ index, gspca_dev->usb_buf, length, 500); if (ret < 0) { PDEBUG(D_ERR, "reg_read err %d", ret); return -1; } return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];}static int write_vector(struct gspca_dev *gspca_dev, const __u16 data[][3]){ struct usb_device *dev = gspca_dev->dev; int ret, i = 0; while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]); if (ret < 0) { PDEBUG(D_ERR, "Register write failed for 0x%x,0x%x,0x%x", data[i][0], data[i][1], data[i][2]); return ret; } i++; } return 0;}static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, unsigned int request, unsigned int ybase, unsigned int cbase, const __u8 qtable[2][64]){ struct usb_device *dev = gspca_dev->dev; int i, err; /* loop over y components */ for (i = 0; i < 64; i++) { err = reg_w_riv(dev, request, ybase + i, qtable[0][i]); if (err < 0) return err; } /* loop over c components */ for (i = 0; i < 64; i++) { err = reg_w_riv(dev, request, cbase + i, qtable[1][i]); if (err < 0) return err; } return 0;}static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, __u16 req, __u16 idx, __u16 val){ struct usb_device *dev = gspca_dev->dev; __u8 notdone; reg_w_riv(dev, req, idx, val); notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); reg_w_riv(dev, req, idx, val); PDEBUG(D_FRAM, "before wait 0x%x", notdone); msleep(200); notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); PDEBUG(D_FRAM, "after wait 0x%x", notdone);}static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, __u16 req, __u16 idx, __u16 val, __u8 stat, __u8 count){ struct usb_device *dev = gspca_dev->dev; __u8 status; __u8 endcode; reg_w_riv(dev, req, idx, val); status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); endcode = stat; PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat); if (!count) return; count = 200; while (--count > 0) { msleep(10); /* gsmart mini2 write a each wait setting 1 ms is enought *//* reg_w_riv(dev, req, idx, val); */ status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); if (status == endcode) { PDEBUG(D_FRAM, "status 0x%x after wait 0x%x", status, 200 - count); break; } }}static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev){ int count = 10; while (--count > 0) { reg_r(gspca_dev, 0x21, 0, 1); if ((gspca_dev->usb_buf[0] & 0x01) == 0) break; msleep(10); } return gspca_dev->usb_buf[0];}static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev){ int count = 50; while (--count > 0) { reg_r(gspca_dev, 0x21, 1, 1); if (gspca_dev->usb_buf[0] != 0) { gspca_dev->usb_buf[0] = 0; reg_w(gspca_dev, 0x21, 0, 1, 1); reg_r(gspca_dev, 0x21, 1, 1); spca504B_PollingDataReady(gspca_dev); break; } msleep(10); }}static void spca50x_GetFirmware(struct gspca_dev *gspca_dev){ __u8 *data; data = gspca_dev->usb_buf; reg_r(gspca_dev, 0x20, 0, 5); PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ", data[0], data[1], data[2], data[3], data[4]); reg_r(gspca_dev, 0x23, 0, 64); reg_r(gspca_dev, 0x23, 1, 64);}static void spca504B_SetSizeType(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; __u8 Size; __u8 Type; int rc; Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; Type = 0; switch (sd->bridge) { case BRIDGE_SPCA533: reg_w(gspca_dev, 0x31, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); spca50x_GetFirmware(gspca_dev); gspca_dev->usb_buf[0] = 2; /* type */ reg_w(gspca_dev, 0x24, 0, 8, 1); reg_r(gspca_dev, 0x24, 8, 1); gspca_dev->usb_buf[0] = Size; reg_w(gspca_dev, 0x25, 0, 4, 1); reg_r(gspca_dev, 0x25, 4, 1); /* size */ rc = spca504B_PollingDataReady(gspca_dev); /* Init the cam width height with some values get on init ? */ reg_w(gspca_dev, 0x31, 0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); break; default:/* case BRIDGE_SPCA504B: *//* case BRIDGE_SPCA536: */ gspca_dev->usb_buf[0] = Size; reg_w(gspca_dev, 0x25, 0, 4, 1); reg_r(gspca_dev, 0x25, 4, 1); /* size */ Type = 6; gspca_dev->usb_buf[0] = Type; reg_w(gspca_dev, 0x27, 0, 0, 1); reg_r(gspca_dev, 0x27, 0, 1); /* type */ rc = spca504B_PollingDataReady(gspca_dev); break; case BRIDGE_SPCA504: Size += 3; if (sd->subtype == AiptekMiniPenCam13) { /* spca504a aiptek */ spca504A_acknowledged_command(gspca_dev, 0x08, Size, 0, 0x80 | (Size & 0x0f), 1); spca504A_acknowledged_command(gspca_dev, 1, 3, 0, 0x9f, 0); } else { spca504_acknowledged_command(gspca_dev, 0x08, Size, 0); } break; case BRIDGE_SPCA504C: /* capture mode */ reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); break; }}static void spca504_wait_status(struct gspca_dev *gspca_dev){ int cnt; cnt = 256; while (--cnt > 0) { /* With this we get the status, when return 0 it's all ok */ if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0) return; msleep(10); }}static void spca504B_setQtable(struct gspca_dev *gspca_dev){ gspca_dev->usb_buf[0] = 3; reg_w(gspca_dev, 0x26, 0, 0, 1); reg_r(gspca_dev, 0x26, 0, 1); spca504B_PollingDataReady(gspca_dev);}static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; int pollreg = 1; switch (sd->bridge) { case BRIDGE_SPCA504: case BRIDGE_SPCA504C: pollreg = 0; /* fall thru */ default:/* case BRIDGE_SPCA533: *//* case BRIDGE_SPCA504B: */ reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */ reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */ reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */ reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */ reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */ reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */ break; case BRIDGE_SPCA536: reg_w(gspca_dev, 0, 0, 0x20f0, 0); reg_w(gspca_dev, 0, 0x21, 0x20f1, 0); reg_w(gspca_dev, 0, 0x40, 0x20f5, 0); reg_w(gspca_dev, 0, 1, 0x20f4, 0); reg_w(gspca_dev, 0, 0x40, 0x20f6, 0); reg_w(gspca_dev, 0, 0, 0x2089, 0); break; } if (pollreg) spca504B_PollingDataReady(gspca_dev);}/* this function is called at probe time */static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id){ struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; cam = &gspca_dev->cam; cam->epaddr = 0x01; sd->bridge = id->driver_info >> 8; sd->subtype = id->driver_info; if (sd->subtype == AiptekMiniPenCam13) {/* try to get the firmware as some cam answer 2.0.1.2.2 * and should be a spca504b then overwrite that setting */ reg_r(gspca_dev, 0x20, 0, 1); switch (gspca_dev->usb_buf[0]) { case 1: break; /* (right bridge/subtype) */ case 2: sd->bridge = BRIDGE_SPCA504B; sd->subtype = 0; break; default: return -ENODEV; } } switch (sd->bridge) { default:/* case BRIDGE_SPCA504B: *//* case BRIDGE_SPCA504: *//* case BRIDGE_SPCA536: */ cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; break; case BRIDGE_SPCA533: cam->cam_mode = custom_mode; cam->nmodes = sizeof custom_mode / sizeof custom_mode[0]; break; case BRIDGE_SPCA504C: cam->cam_mode = vga_mode2; cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0]; break; } sd->qindex = 5; /* set the quantization table */ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; return 0;}/* this function is called at probe and resume time */static int sd_init(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; int rc; __u8 i; __u8 info[6]; int err_code; switch (sd->bridge) { case BRIDGE_SPCA504B: reg_w(gspca_dev, 0x1d, 0, 0, 0); reg_w(gspca_dev, 0, 1, 0x2306, 0); reg_w(gspca_dev, 0, 0, 0x0d04, 0); reg_w(gspca_dev, 0, 0, 0x2000, 0); reg_w(gspca_dev, 0, 0x13, 0x2301, 0); reg_w(gspca_dev, 0, 0, 0x2306, 0); /* fall thru */ case BRIDGE_SPCA533: rc = spca504B_PollingDataReady(gspca_dev); spca50x_GetFirmware(gspca_dev); break; case BRIDGE_SPCA536: spca50x_GetFirmware(gspca_dev); reg_r(gspca_dev, 0x00, 0x5002, 1); gspca_dev->usb_buf[0] = 0; reg_w(gspca_dev, 0x24, 0, 0, 1); reg_r(gspca_dev, 0x24, 0, 1); rc = spca504B_PollingDataReady(gspca_dev); reg_w(gspca_dev, 0x34, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); break; case BRIDGE_SPCA504C: /* pccam600 */ PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)"); reg_w_riv(dev, 0xe0, 0x0000, 0x0000); reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */ spca504_wait_status(gspca_dev); if (sd->subtype == LogitechClickSmart420) write_vector(gspca_dev, spca504A_clicksmart420_open_data); else write_vector(gspca_dev, spca504_pccam600_open_data); err_code = spca50x_setup_qtable(gspca_dev, 0x00, 0x2800, 0x2840, qtable_creative_pccam); if (err_code < 0) { PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed"); return err_code; } break; default:/* case BRIDGE_SPCA504: */ PDEBUG(D_STREAM, "Opening SPCA504"); if (sd->subtype == AiptekMiniPenCam13) { /*****************************/ for (i = 0; i < 6; i++) info[i] = reg_r_1(gspca_dev, i); PDEBUG(D_STREAM, "Read info: %d %d %d %d %d %d." " Should be 1,0,2,2,0,0", info[0], info[1], info[2], info[3], info[4], info[5]); /* spca504a aiptek */ /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ spca504A_acknowledged_command(gspca_dev, 0x24, 8, 3, 0x9e, 1); /* Twice sequencial need status 0xff->0x9e->0x9d */ spca504A_acknowledged_command(gspca_dev, 0x24, 8, 3, 0x9e, 0); spca504A_acknowledged_command(gspca_dev, 0x24, 0, 0, 0x9d, 1); /******************************/ /* spca504a aiptek */ spca504A_acknowledged_command(gspca_dev, 0x08, 6, 0, 0x86, 1);/* reg_write (dev, 0, 0x2000, 0); *//* reg_write (dev, 0, 0x2883, 1); *//* spca504A_acknowledged_command (gspca_dev, 0x08, 6, 0, 0x86, 1); *//* spca504A_acknowledged_command (gspca_dev, 0x24, 0, 0, 0x9D, 1); */ reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */ reg_w_riv(dev, 0x0, 0x2310, 0x05); spca504A_acknowledged_command(gspca_dev, 0x01, 0x0f, 0, 0xff, 0); } /* setup qtable */ reg_w_riv(dev, 0, 0x2000, 0); reg_w_riv(dev, 0, 0x2883, 1); err_code = spca50x_setup_qtable(gspca_dev, 0x00, 0x2800, 0x2840, qtable_spca504_default); if (err_code < 0) { PDEBUG(D_ERR, "spca50x_setup_qtable failed"); return err_code; } break; } return 0;}static int sd_start(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; int rc; int enable; __u8 i; __u8 info[6]; if (sd->bridge == BRIDGE_SPCA504B) spca504B_setQtable(gspca_dev); spca504B_SetSizeType(gspca_dev); switch (sd->bridge) { default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -