pac7311.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,121 行 · 第 1/2 页
C
1,121 行
v = 0xff; reg_w(gspca_dev, 0xa2 + i, v); } reg_w(gspca_dev, 0xdc, 0x01);}/* This function is used by pac7311 only */static void setcontrast(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x10, sd->contrast >> 4); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01);}/* This function is used by pac7302 only */static void setcolors(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; int i, v; static const int a[9] = {217, -212, 0, -101, 170, -67, -38, -315, 355}; static const int b[9] = {19, 106, 0, 19, 106, 1, 19, 106, 1}; reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ reg_w(gspca_dev, 0x11, 0x01); reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ for (i = 0; i < 9; i++) { v = a[i] * sd->colors / COLOR_MAX + b[i]; reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); reg_w(gspca_dev, 0x0f + 2 * i + 1, v); } reg_w(gspca_dev, 0xdc, 0x01); PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);}static void setgain(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; if (sd->sensor == SENSOR_PAC7302) { reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ reg_w(gspca_dev, 0x10, sd->gain >> 3); } else { int gain = GAIN_MAX - sd->gain; if (gain < 1) gain = 1; else if (gain > 245) gain = 245; reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ reg_w(gspca_dev, 0x0e, 0x00); reg_w(gspca_dev, 0x0f, gain); } /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01);}static void setexposure(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; __u8 reg; /* register 2 of frame 3/4 contains the clock divider configuring the no fps according to the formula: 60 / reg. sd->exposure is the desired exposure time in ms. */ reg = 120 * sd->exposure / 1000; if (reg < 2) reg = 2; else if (reg > 63) reg = 63; if (sd->sensor == SENSOR_PAC7302) { /* On the pac7302 reg2 MUST be a multiple of 3, so round it to the nearest multiple of 3, except when between 6 and 12? */ if (reg < 6 || reg > 12) reg = ((reg + 1) / 3) * 3; reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ reg_w(gspca_dev, 0x02, reg); } else { reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ reg_w(gspca_dev, 0x02, reg); /* Page 1 register 8 must always be 0x08 except when not in 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */ reg_w(gspca_dev, 0xff, 0x01); if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv && reg <= 3) reg_w(gspca_dev, 0x08, 0x09); else reg_w(gspca_dev, 0x08, 0x08); } /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01);}static void sethvflip(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; __u8 data; if (sd->sensor == SENSOR_PAC7302) { reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ data = (sd->hflip ? 0x08 : 0x00) | (sd->vflip ? 0x04 : 0x00); } else { reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00); } reg_w(gspca_dev, 0x21, data); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01);}/* 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; if (sd->sensor == SENSOR_PAC7302) reg_w_seq(gspca_dev, init_7302, sizeof init_7302); else reg_w_seq(gspca_dev, init_7311, sizeof init_7311); return 0;}static int sd_start(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; sd->sof_read = 0; if (sd->sensor == SENSOR_PAC7302) { reg_w_var(gspca_dev, start_7302); setbrightcont(gspca_dev); setcolors(gspca_dev); } else { reg_w_var(gspca_dev, start_7311); setcontrast(gspca_dev); } setgain(gspca_dev); setexposure(gspca_dev); sethvflip(gspca_dev); /* set correct resolution */ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { case 2: /* 160x120 pac7311 */ reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x17, 0x20); reg_w(gspca_dev, 0x87, 0x10); break; case 1: /* 320x240 pac7311 */ reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x17, 0x30); reg_w(gspca_dev, 0x87, 0x11); break; case 0: /* 640x480 */ if (sd->sensor == SENSOR_PAC7302) break; reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x17, 0x00); reg_w(gspca_dev, 0x87, 0x12); break; } sd->sof_read = 0; sd->autogain_ignore_frames = 0; atomic_set(&sd->avg_lum, -1); /* start stream */ reg_w(gspca_dev, 0xff, 0x01); if (sd->sensor == SENSOR_PAC7302) reg_w(gspca_dev, 0x78, 0x01); else reg_w(gspca_dev, 0x78, 0x05); return 0;}static void sd_stopN(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; if (sd->sensor == SENSOR_PAC7302) { reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x78, 0x00); reg_w(gspca_dev, 0x78, 0x00); return; } reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x27, 0x80); reg_w(gspca_dev, 0x28, 0xca); reg_w(gspca_dev, 0x29, 0x53); reg_w(gspca_dev, 0x2a, 0x0e); reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x3e, 0x20); reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */}static void sd_stop0(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; if (sd->sensor == SENSOR_PAC7302) { reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x78, 0x40); }}/* Include pac common sof detection functions */#include "pac_common.h"static void do_autogain(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; int avg_lum = atomic_read(&sd->avg_lum); int desired_lum, deadzone; if (avg_lum == -1) return; if (sd->sensor == SENSOR_PAC7302) { desired_lum = 270 + sd->brightness * 4; /* Hack hack, with the 7202 the first exposure step is pretty large, so if we're about to make the first exposure increase make the deadzone large to avoid oscilating */ if (desired_lum > avg_lum && sd->gain == GAIN_DEF && sd->exposure > EXPOSURE_DEF && sd->exposure < 42) deadzone = 90; else deadzone = 30; } else { desired_lum = 200; deadzone = 20; } if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, deadzone, GAIN_KNEE, EXPOSURE_KNEE)) sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;}static const unsigned char pac7311_jpeg_header1[] = { 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08};static const unsigned char pac7311_jpeg_header2[] = { 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00};/* this function is run at interrupt level */static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */{ struct sd *sd = (struct sd *) gspca_dev; unsigned char *sof; sof = pac_find_sof(gspca_dev, data, len); if (sof) { unsigned char tmpbuf[4]; int n, lum_offset, footer_length; if (sd->sensor == SENSOR_PAC7302) { /* 6 bytes after the FF D9 EOF marker a number of lumination bytes are send corresponding to different parts of the image, the 14th and 15th byte after the EOF seem to correspond to the center of the image */ lum_offset = 61 + sizeof pac_sof_marker; footer_length = 74; } else { lum_offset = 24 + sizeof pac_sof_marker; footer_length = 26; } /* Finish decoding current frame */ n = (sof - data) - (footer_length + sizeof pac_sof_marker); if (n < 0) { frame->data_end += n; n = 0; } frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, n); if (gspca_dev->last_packet_type != DISCARD_PACKET && frame->data_end[-2] == 0xff && frame->data_end[-1] == 0xd9) frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0); n = sof - data; len -= n; data = sof; /* Get average lumination */ if (gspca_dev->last_packet_type == LAST_PACKET && n >= lum_offset) atomic_set(&sd->avg_lum, data[-lum_offset] + data[-lum_offset + 1]); else atomic_set(&sd->avg_lum, -1); /* Start the new frame with the jpeg header */ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1)); if (sd->sensor == SENSOR_PAC7302) { /* The PAC7302 has the image rotated 90 degrees */ tmpbuf[0] = gspca_dev->width >> 8; tmpbuf[1] = gspca_dev->width & 0xff; tmpbuf[2] = gspca_dev->height >> 8; tmpbuf[3] = gspca_dev->height & 0xff; } else { tmpbuf[0] = gspca_dev->height >> 8; tmpbuf[1] = gspca_dev->height & 0xff; tmpbuf[2] = gspca_dev->width >> 8; tmpbuf[3] = gspca_dev->width & 0xff; } gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4); gspca_frame_add(gspca_dev, INTER_PACKET, frame, pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2)); } gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);}static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->brightness = val; if (gspca_dev->streaming) setbrightcont(gspca_dev); return 0;}static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->brightness; return 0;}static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->contrast = val; if (gspca_dev->streaming) { if (sd->sensor == SENSOR_PAC7302) setbrightcont(gspca_dev); else setcontrast(gspca_dev); } return 0;}static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->contrast; return 0;}static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->colors = val; if (gspca_dev->streaming) setcolors(gspca_dev); return 0;}static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->colors; return 0;}static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->gain = val; if (gspca_dev->streaming) setgain(gspca_dev); return 0;}static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->gain; return 0;}static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->exposure = val; if (gspca_dev->streaming) setexposure(gspca_dev); return 0;}static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->exposure; return 0;}static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; /* when switching to autogain set defaults to make sure we are on a valid point of the autogain gain / exposure knee graph, and give this change time to take effect before doing autogain. */ if (sd->autogain) { sd->exposure = EXPOSURE_DEF; sd->gain = GAIN_DEF; if (gspca_dev->streaming) { sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; setexposure(gspca_dev); setgain(gspca_dev); } } return 0;}static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->autogain; return 0;}static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->hflip = val; if (gspca_dev->streaming) sethvflip(gspca_dev); return 0;}static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->hflip; return 0;}static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->vflip = val; if (gspca_dev->streaming) sethvflip(gspca_dev); return 0;}static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->vflip; return 0;}/* sub-driver description */static struct sd_desc sd_desc = { .name = MODULE_NAME, .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain,};/* -- module initialisation -- */static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302}, {}};MODULE_DEVICE_TABLE(usb, device_table);/* -- device connect -- */static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id){ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), THIS_MODULE);}static struct usb_driver sd_driver = { .name = MODULE_NAME, .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect,#ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume,#endif};/* -- module insert / remove -- */static int __init sd_mod_init(void){ if (usb_register(&sd_driver) < 0) return -1; PDEBUG(D_PROBE, "registered"); return 0;}static void __exit sd_mod_exit(void){ usb_deregister(&sd_driver); PDEBUG(D_PROBE, "deregistered");}module_init(sd_mod_init);module_exit(sd_mod_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?