📄 konicawc.c
字号:
/* * konicawc.c - konica webcam driver * * Author: Simon Evans <spse@secret.org.uk> * * Copyright (C) 2002 Simon Evans * * Licence: GPL * * Driver for USB webcams based on Konica chipset. This * chipset is used in Intel YC76 camera. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/input.h>#include <linux/usb_input.h>#include "usbvideo.h"#define MAX_BRIGHTNESS 108#define MAX_CONTRAST 108#define MAX_SATURATION 108#define MAX_SHARPNESS 108#define MAX_WHITEBAL 372#define MAX_SPEED 6#define MAX_CAMERAS 1#define DRIVER_VERSION "v1.4"#define DRIVER_DESC "Konica Webcam driver"enum ctrl_req { SetWhitebal = 0x01, SetBrightness = 0x02, SetSharpness = 0x03, SetContrast = 0x04, SetSaturation = 0x05,};enum frame_sizes { SIZE_160X120 = 0, SIZE_160X136 = 1, SIZE_176X144 = 2, SIZE_320X240 = 3, };#define MAX_FRAME_SIZE SIZE_320X240static struct usbvideo *cams;#ifdef CONFIG_USB_DEBUGstatic int debug;#define DEBUG(n, format, arg...) \ if (n <= debug) { \ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \ }#else#define DEBUG(n, arg...)static const int debug = 0;#endif/* Some default values for initial camera settings, can be set by modprobe */static int size; static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */static int brightness = MAX_BRIGHTNESS/2;static int contrast = MAX_CONTRAST/2;static int saturation = MAX_SATURATION/2;static int sharpness = MAX_SHARPNESS/2;static int whitebal = 3*(MAX_WHITEBAL/4);static int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };/* These FPS speeds are from the windows config box. They are * indexed on size (0-2) and speed (0-6). Divide by 3 to get the * real fps. */static int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 }, { 24, 40, 48, 60, 72, 80, 100 }, { 18, 30, 36, 45, 54, 60, 75 }, { 6, 10, 12, 15, 18, 21, 25 } };struct cam_size { u16 width; u16 height; u8 cmd;};static struct cam_size camera_sizes[] = { { 160, 120, 0x7 }, { 160, 136, 0xa }, { 176, 144, 0x4 }, { 320, 240, 0x5 } };struct konicawc { u8 brightness; /* camera uses 0 - 9, x11 for real value */ u8 contrast; /* as above */ u8 saturation; /* as above */ u8 sharpness; /* as above */ u8 white_bal; /* 0 - 33, x11 for real value */ u8 speed; /* Stored as 0 - 6, used as index in spd_to_* (above) */ u8 size; /* Frame Size */ int height; int width; struct urb *sts_urb[USBVIDEO_NUMSBUF]; u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC]; struct urb *last_data_urb; int lastframe; int cur_frame_size; /* number of bytes in current frame size */ int maxline; /* number of lines per frame */ int yplanesz; /* Number of bytes in the Y plane */ unsigned int buttonsts:1;#ifdef CONFIG_INPUT struct input_dev *input; char input_physname[64];#endif};#define konicawc_set_misc(uvd, req, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)#define konicawc_get_misc(uvd, req, value, index, buf, sz) konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)#define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len){ int retval = usb_control_msg(uvd->dev, dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0), request, 0x40 | dir, value, index, buf, len, 1000); return retval < 0 ? retval : 0;}static inline void konicawc_camera_on(struct uvd *uvd){ DEBUG(0, "camera on"); konicawc_set_misc(uvd, 0x2, 1, 0x0b);}static inline void konicawc_camera_off(struct uvd *uvd){ DEBUG(0, "camera off"); konicawc_set_misc(uvd, 0x2, 0, 0x0b);}static void konicawc_set_camera_size(struct uvd *uvd){ struct konicawc *cam = (struct konicawc *)uvd->user_data; konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08); cam->width = camera_sizes[cam->size].width; cam->height = camera_sizes[cam->size].height; cam->yplanesz = cam->height * cam->width; cam->cur_frame_size = (cam->yplanesz * 3) / 2; cam->maxline = cam->yplanesz / 256; uvd->videosize = VIDEOSIZE(cam->width, cam->height);}static int konicawc_setup_on_open(struct uvd *uvd){ struct konicawc *cam = (struct konicawc *)uvd->user_data; DEBUG(1, "setting brightness to %d (%d)", cam->brightness, cam->brightness * 11); konicawc_set_value(uvd, cam->brightness, SetBrightness); DEBUG(1, "setting white balance to %d (%d)", cam->white_bal, cam->white_bal * 11); konicawc_set_value(uvd, cam->white_bal, SetWhitebal); DEBUG(1, "setting contrast to %d (%d)", cam->contrast, cam->contrast * 11); konicawc_set_value(uvd, cam->contrast, SetContrast); DEBUG(1, "setting saturation to %d (%d)", cam->saturation, cam->saturation * 11); konicawc_set_value(uvd, cam->saturation, SetSaturation); DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness, cam->sharpness * 11); konicawc_set_value(uvd, cam->sharpness, SetSharpness); konicawc_set_camera_size(uvd); cam->lastframe = -2; cam->buttonsts = 0; return 0;}static void konicawc_adjust_picture(struct uvd *uvd){ struct konicawc *cam = (struct konicawc *)uvd->user_data; konicawc_camera_off(uvd); DEBUG(1, "new brightness: %d", uvd->vpic.brightness); uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness; if(cam->brightness != uvd->vpic.brightness / 11) { cam->brightness = uvd->vpic.brightness / 11; DEBUG(1, "setting brightness to %d (%d)", cam->brightness, cam->brightness * 11); konicawc_set_value(uvd, cam->brightness, SetBrightness); } DEBUG(1, "new contrast: %d", uvd->vpic.contrast); uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast; if(cam->contrast != uvd->vpic.contrast / 11) { cam->contrast = uvd->vpic.contrast / 11; DEBUG(1, "setting contrast to %d (%d)", cam->contrast, cam->contrast * 11); konicawc_set_value(uvd, cam->contrast, SetContrast); } konicawc_camera_on(uvd);}#ifdef CONFIG_INPUTstatic void konicawc_register_input(struct konicawc *cam, struct usb_device *dev){ struct input_dev *input_dev; usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname)); strncat(cam->input_physname, "/input0", sizeof(cam->input_physname)); cam->input = input_dev = input_allocate_device(); if (!input_dev) { warn("Not enough memory for camera's input device\n"); return; } input_dev->name = "Konicawc snapshot button"; input_dev->phys = cam->input_physname; usb_to_input_id(dev, &input_dev->id); input_dev->cdev.dev = &dev->dev; input_dev->evbit[0] = BIT(EV_KEY); input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); input_dev->private = cam; input_register_device(cam->input);}static void konicawc_unregister_input(struct konicawc *cam){ if (cam->input) { input_unregister_device(cam->input); cam->input = NULL; }}static void konicawc_report_buttonstat(struct konicawc *cam){ if (cam->input) { input_report_key(cam->input, BTN_0, cam->buttonsts); input_sync(cam->input); }}#elsestatic inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { }static inline void konicawc_unregister_input(struct konicawc *cam) { }static inline void konicawc_report_buttonstat(struct konicawc *cam) { }#endif /* CONFIG_INPUT */static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb){ char *cdata; int i, totlen = 0; unsigned char *status = stsurb->transfer_buffer; int keep = 0, discard = 0, bad = 0; struct konicawc *cam = (struct konicawc *)uvd->user_data; for (i = 0; i < dataurb->number_of_packets; i++) { int button = cam->buttonsts; unsigned char sts; int n = dataurb->iso_frame_desc[i].actual_length; int st = dataurb->iso_frame_desc[i].status; cdata = dataurb->transfer_buffer + dataurb->iso_frame_desc[i].offset; /* Detect and ignore errored packets */ if (st < 0) { DEBUG(1, "Data error: packet=%d. len=%d. status=%d.", i, n, st); uvd->stats.iso_err_count++; continue; } /* Detect and ignore empty packets */ if (n <= 0) { uvd->stats.iso_skip_count++; continue; } /* See what the status data said about the packet */ sts = *(status+stsurb->iso_frame_desc[i].offset); /* sts: 0x80-0xff: frame start with frame number (ie 0-7f) * otherwise: * bit 0 0: keep packet * 1: drop packet (padding data) * * bit 4 0 button not clicked * 1 button clicked * button is used to `take a picture' (in software) */ if(sts < 0x80) { button = !!(sts & 0x40); sts &= ~0x40; } /* work out the button status, but don't do anything with it for now */ if(button != cam->buttonsts) { DEBUG(2, "button: %sclicked", button ? "" : "un"); cam->buttonsts = button; konicawc_report_buttonstat(cam); } if(sts == 0x01) { /* drop frame */ discard++; continue; } if((sts > 0x01) && (sts < 0x80)) { info("unknown status %2.2x", sts); bad++; continue; } if(!sts && cam->lastframe == -2) { DEBUG(2, "dropping frame looking for image start"); continue; } keep++; if(sts & 0x80) { /* frame start */ unsigned char marker[] = { 0, 0xff, 0, 0x00 }; if(cam->lastframe == -2) { DEBUG(2, "found initial image"); cam->lastframe = -1; } marker[3] = sts & 0x7F; RingQueue_Enqueue(&uvd->dp, marker, 4); totlen += 4; } totlen += n; /* Little local accounting */ RingQueue_Enqueue(&uvd->dp, cdata, n); } DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes", keep, discard, bad, totlen); return totlen;}static void resubmit_urb(struct uvd *uvd, struct urb *urb){ int i, ret; for (i = 0; i < FRAMES_PER_DESC; i++) { urb->iso_frame_desc[i].status = 0; } urb->dev = uvd->dev; urb->status = 0; ret = usb_submit_urb(urb, GFP_ATOMIC); DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length); if(ret) err("usb_submit_urb error (%d)", ret);}static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs){ struct uvd *uvd = urb->context; struct konicawc *cam = (struct konicawc *)uvd->user_data; /* We don't want to do anything if we are about to be removed! */ if (!CAMERA_IS_OPERATIONAL(uvd)) return; if (!uvd->streaming) { DEBUG(1, "Not streaming, but interrupt!"); return; } DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length); uvd->stats.urb_count++; if (urb->transfer_buffer_length > 32) { cam->last_data_urb = urb; return; } /* Copy the data received into ring queue */ if(cam->last_data_urb) { int len = 0; if(urb->start_frame != cam->last_data_urb->start_frame) err("Lost sync on frames"); else if (!urb->status && !cam->last_data_urb->status) len = konicawc_compress_iso(uvd, cam->last_data_urb, urb); resubmit_urb(uvd, cam->last_data_urb); resubmit_urb(uvd, urb); cam->last_data_urb = NULL; uvd->stats.urb_length = len; uvd->stats.data_count += len; if(len) RingQueue_WakeUpInterruptible(&uvd->dp); return; } return;}static int konicawc_start_data(struct uvd *uvd){ struct usb_device *dev = uvd->dev; int i, errFlag; struct konicawc *cam = (struct konicawc *)uvd->user_data; int pktsz; struct usb_interface *intf; struct usb_host_interface *interface = NULL; intf = usb_ifnum_to_if(dev, uvd->iface); if (intf) interface = usb_altnum_to_altsetting(intf, spd_to_iface[cam->speed]); if (!interface) return -ENXIO; pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize); DEBUG(1, "pktsz = %d", pktsz); if (!CAMERA_IS_OPERATIONAL(uvd)) { err("Camera is not operational"); return -EFAULT; } uvd->curframe = -1; konicawc_camera_on(uvd); /* Alternate interface 1 is is the biggest frame size */ i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); if (i < 0) { err("usb_set_interface error"); uvd->last_error = i; return -EBUSY; } /* We double buffer the Iso lists */ for (i=0; i < USBVIDEO_NUMSBUF; i++) { int j, k; struct urb *urb = uvd->sbuf[i].urb; urb->dev = dev; urb->context = uvd; urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); urb->interval = 1; urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = uvd->sbuf[i].data; urb->complete = konicawc_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC; for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) { urb->iso_frame_desc[j].offset = k; urb->iso_frame_desc[j].length = pktsz; } urb = cam->sts_urb[i]; urb->dev = dev; urb->context = uvd; urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1); urb->interval = 1; urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = cam->sts_buf[i]; urb->complete = konicawc_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; urb->transfer_buffer_length = FRAMES_PER_DESC; for (j=0; j < FRAMES_PER_DESC; j++) { urb->iso_frame_desc[j].offset = j; urb->iso_frame_desc[j].length = 1; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -