lkml.org 
[lkml]   [2002]   [Oct]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectVicam/3com homeconnect usb camera driver
Attached is a driver for the 3Com HomeConnect USB Camera. The code is
based somewhat on the vicam driver in the kernel (which crashes my
computer hard) and also relies heavily on the information obtained by
the guys doing the reverse engineering and kernel driver work at
homeconnectusb.sourceforge.net. The fact that this driver works speaks
very highly of them.

The driver gets the "It Works for Me" approval, but can definitely use
some wider testing and review. Please test, review, and comment.

The code is for for 2.4.19, and I'll port it forward to 2.5 if it
seems like it would be useful.

Apologies:
1. The files are not a patch but should build outside of the tree.
2. The file is woefully underdocumented
3. There aren't any printk's in the driver.

I'm not subscribed to the list but rather lurk on the archives, so please
try to include me in any replies.

Thanks,
John
/* -*- linux-c -*-
* vicam.c - ViCAM/3Com HomeConnect USB Camera Driver
*
* Copyright (c) 2002 John Tyner <jtyner@cs.ucr.edu>
*/

#ifndef VICAM_H
#define VICAM_H

#define clamp( x, l, h ) max_t( long, min_t( long, ( x ), ( h ) ), ( l ) )

#define DEBUG_PRINT( format, args... ) \
printk( KERN_DEBUG __FUNCTION__ ": " format, ##args )

#define USB_3COMHC_VENDOR_ID 0x04C1
#define USB_3COMHC_PRODUCT_ID 0x009D

#define VICAM_HEADER_SIZE 64
#define VICAM_FOOTER_SIZE 64

#define VICAM_NUM_FRAMES 4
#define VICAM_FRAME_SIZE ( 3 * 320 * 242 )
#define VICAM_INPUT_SIZE ( 512 * 242 + \
VICAM_HEADER_SIZE + VICAM_FOOTER_SIZE )

#define VICAM_CNTRL_BUF_SIZE PAGE_SIZE
#define VICAM_FRAME_BUF_SIZE PAGE_ALIGN( VICAM_NUM_FRAMES * \
VICAM_FRAME_SIZE )

#define VICAM_REQ_VENDOR 0xFF
#define VICAM_REQ_POWER 0x50
#define VICAM_REQ_CAPTURE 0x51
#define VICAM_REQ_LED 0x55

struct vicam_usb_data {
struct video_device vicam_v4l_dev;
};

struct vicam_v4l_data {
struct usb_device *usb_dev;
struct urb *urb;
struct semaphore dev_mutex;
struct semaphore busy_mutex;
struct semaphore decode_mutex[VICAM_NUM_FRAMES];
struct tasklet_struct decode;
u8 *cntrl_buf;
u8 *input_buf[VICAM_NUM_FRAMES];
u8 *frame_buf;
unsigned long current_frame;
unsigned long decode_frames;
u32 width, height;
u16 speed;
u8 gain;
u8 bulk_endpoint;
};

static const u8 setup1[] = {
0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
};

static const u8 setup2[] = {
0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
0x00, 0x00
};

static const u8 setup3[] = {
0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
};

static const u8 setup4[] = {
0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const u8 setup5[] = {
0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
};

static const u8 setup6[] = {
0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
};

static const struct {
const u8 * const firmware;
const size_t size;
} setup[] = {
{
.firmware = setup1,
.size = sizeof( setup1 )
}, {
.firmware = setup2,
.size = sizeof( setup2 )
}, {
.firmware = setup3,
.size = sizeof( setup3 )
}, {
.firmware = setup4,
.size = sizeof( setup4 )
}, {
.firmware = setup5,
.size = sizeof( setup5 )
}, {
.firmware = setup6,
.size = sizeof( setup6 )
}, {
.firmware = NULL,
.size = 0
}
};

static inline unsigned long kvirt_to_pa(unsigned long adr)
{
unsigned long kva, ret;

kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
kva |= adr & (PAGE_SIZE-1); /* restore the offset */
ret = __pa(kva);
return ret;
}

static void *rvmalloc(unsigned long size)
{
void *mem;
unsigned long adr;

size = PAGE_ALIGN(size);

mem = vmalloc_32(size);
if (!mem)
return NULL;

memset(mem, 0, size); /* Clear the ram out, no junk to the user */
adr = (unsigned long) mem;
while ((long) size > 0) {
mem_map_reserve(vmalloc_to_page((void *)adr));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}

return mem;
}

static void rvfree(void *mem, unsigned long size)
{
unsigned long adr;

if (!mem)
return;

size = PAGE_ALIGN(size);

adr = (unsigned long) mem;
while ((long) size > 0) {
mem_map_unreserve(vmalloc_to_page((void *)adr));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}

vfree(mem);
}

#endif
/* -*- linux-c -*-
* vicam.c - ViCAM/3Com HomeConnect USB Camera Driver
*
* Copyright (c) 2002 John Tyner <jtyner@cs.ucr.edu>
*
* This driver is for the 3Com HomeConnect USB Camera and
* as far as I know, the Vista Imaging ViCAM Camera. The
* code is based on the driver created by the team at
* homeconnectusb.sourceforge.net. They deserve the credit
* for the decoding algorithm and for figuring out what values
* and messages need to be sent to the camera and what data
* is actually coming back.
*
* This file is woefully underdocumented and doesn't print
* any information. I apologize for that, but the driver is
* working (for me), and doesn't need them. *duck*
*/

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/videodev.h>
#include <linux/vmalloc.h>
#include <linux/wrapper.h>

#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#include "vicam.h"

int reverse_rgb = 0;
int shutter_speed = 30;

static int vicam_send_control_msg( struct vicam_v4l_data *vicam_v4l_priv,
u8 request, u16 value, u16 size )
{
struct usb_device *usb_dev = vicam_v4l_priv->usb_dev;
int ret;

/* for some reason we can't pass data directly
* to usb_control_msg. therefore, we assume that
* the caller has already placed their data into
* the cntrl_buf.
*/

ret = usb_control_msg(
usb_dev,
usb_sndctrlpipe( usb_dev, 0 ),
request,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value,
0,
vicam_v4l_priv->cntrl_buf,
size,
HZ );

return min( ret, 0 );
}

static void vicam_urb_complete( struct urb *vicam_v4l_urb )
{
struct vicam_v4l_data *vicam_v4l_priv;

vicam_v4l_priv = vicam_v4l_urb->context;

if ( !vicam_v4l_urb->status ) {
set_bit( vicam_v4l_priv->current_frame,
&vicam_v4l_priv->decode_frames );
tasklet_schedule( &vicam_v4l_priv->decode );
}

up( &vicam_v4l_priv->busy_mutex );
}

static int vicam_capture_image( struct vicam_v4l_data *vicam_v4l_priv,
unsigned long frame_num )
{
u8 * const request = vicam_v4l_priv->cntrl_buf;
int err;

if ( vicam_v4l_priv->speed < 2 || vicam_v4l_priv->speed > 60 ) {
return -EINVAL;
}

memset( request, 0, 16 );

request[0] = vicam_v4l_priv->gain;

if ( vicam_v4l_priv->width <= 256 ) {
request[1] |= ( vicam_v4l_priv->width > 128 ) ? 0x01 : 0x03;
}

if ( vicam_v4l_priv->height <= 180 ) {
request[1] |= ( vicam_v4l_priv->height > 121 ) ? 0x20 : 0x30;
}

request[2] = 0x90;
request[3] = 0x07;

*( ( u16 * )( &request[6] ) ) =
cpu_to_le16( 15600 / vicam_v4l_priv->speed - 1 );

err = down_interruptible( &vicam_v4l_priv->busy_mutex );
if ( err ) {
return err;
}

vicam_v4l_priv->current_frame = frame_num;

err = vicam_send_control_msg( vicam_v4l_priv,
VICAM_REQ_CAPTURE,
0x80,
16 );

if ( err ) {
goto done;
}

usb_fill_bulk_urb( vicam_v4l_priv->urb,
vicam_v4l_priv->usb_dev,
usb_rcvbulkpipe( vicam_v4l_priv->usb_dev,
vicam_v4l_priv->bulk_endpoint ),
vicam_v4l_priv->input_buf[frame_num],
vicam_v4l_priv->width * vicam_v4l_priv->height +
VICAM_HEADER_SIZE + VICAM_FOOTER_SIZE,
vicam_urb_complete,
vicam_v4l_priv );

err = usb_submit_urb( vicam_v4l_priv->urb );

done:
if ( err ) {
up( &vicam_v4l_priv->busy_mutex );
}

return err;
}

static void vicam_decode_frame( struct vicam_v4l_data *vicam_v4l_priv,
unsigned long frame_num )
{
const u32 width = vicam_v4l_priv->width,
height = vicam_v4l_priv->height;
u8 *ibuf, *obuf;
int y;

ibuf = &vicam_v4l_priv->input_buf[frame_num][VICAM_HEADER_SIZE];
obuf = vicam_v4l_priv->frame_buf + ( VICAM_FRAME_SIZE * frame_num );

for ( y = 0; y < height; y++, ibuf += width ) {
int dy = width;
int x_out;

if ( unlikely( y >= height - 1 ) ) {
dy = -dy;
}

for ( x_out = 0; x_out < 320; x_out++ ) {
int dx, cx, cy, luma, x, i;
int rgbc[3];
u8 sp[4];

x = ( x_out * width ) / 320;

dx = 1;

if ( unlikely( x >= width - 1 ) ) {
dx = -dx;
}

i = ( y & 1 ) | ( ( x & 1 ) << 1 );

sp[i ^ 0] = ibuf[x];
sp[i ^ 1] = ibuf[x + dy];
sp[i ^ 2] = ibuf[x + dx];
sp[i ^ 3] = ibuf[x + dy + dx];

cx = sp[3] - sp[1];
cy = sp[2] - sp[0];

rgbc[0] = cy + ( cx / 2 );

cy /= -2;
cx *= 13; cx /= 15;

rgbc[1] = cy + cx;
rgbc[2] = cy - cx;

luma = ( int )( ibuf[x] + ibuf[x + dx] ) >> 1;

for ( i = 0; i < 3; i++, obuf++ ) {
int j = i;

if ( reverse_rgb ) {
j = ( 2 - i );
}

*obuf = clamp( luma + rgbc[j], 0, 255 );
}
}
}

up( &vicam_v4l_priv->decode_mutex[frame_num] );
}

static void vicam_bh_handler( unsigned long _vicam_v4l_priv )
{
struct vicam_v4l_data *vicam_v4l_priv =
( struct vicam_v4l_data * )( _vicam_v4l_priv );
int i;

do {
i = ffs( vicam_v4l_priv->decode_frames );
vicam_decode_frame( vicam_v4l_priv, i - 1 );
clear_bit( i - 1, &vicam_v4l_priv->decode_frames );
} while ( vicam_v4l_priv->decode_frames );
}

static int vicam_v4l_open( struct video_device *dev, int mode )
{
struct vicam_v4l_data *vicam_v4l_priv = dev->priv;
int err;

err = down_interruptible( &vicam_v4l_priv->dev_mutex );
if ( err ) {
return err;
}

err = vicam_send_control_msg( vicam_v4l_priv, VICAM_REQ_POWER, 1, 0 );
vicam_send_control_msg( vicam_v4l_priv, VICAM_REQ_LED, 3, 0 );

if ( err ) {
up( &vicam_v4l_priv->dev_mutex );
}

return err;
}

static void vicam_v4l_close( struct video_device *dev )
{
struct vicam_v4l_data *vicam_v4l_priv = dev->priv;

vicam_send_control_msg( vicam_v4l_priv, VICAM_REQ_POWER, 0, 0 );

up( &vicam_v4l_priv->dev_mutex );
}

static long vicam_v4l_write( struct video_device *dev, const char *buf,
unsigned long count, int noblock )
{
return -EPERM;
}

static int vicam_v4l_ioctl( struct video_device *dev, unsigned int cmd,
void *arg )
{
struct vicam_v4l_data *vicam_v4l_priv;
struct video_capability *vcap;
struct video_channel *vchan;
struct video_mbuf *vmbuf;
struct video_picture *vpic;
struct video_mmap *vmmap;
struct video_window *vwin;
void *buf;
int buf_size, err, i;

vicam_v4l_priv = dev->priv;

err = 0;

buf_size = max_t( int, sizeof( *vcap ),
max_t( int, sizeof( *vchan ),
max_t( int, sizeof( *vmbuf ),
max_t( int, sizeof( *vpic ),
max_t( int, sizeof( *vmmap ),
sizeof( *vwin ) ) ) ) ) );

if ( unlikely( buf_size > VICAM_CNTRL_BUF_SIZE ) ) {
return -ENOMEM;
}

buf = vicam_v4l_priv->cntrl_buf;
buf_size = 0;

vcap = buf;
vchan = buf;
vmbuf = buf;
vpic = buf;
vmmap = buf;
vwin = buf;

switch ( cmd ) {
case VIDIOCGCAP:
buf_size = sizeof( *vcap );

memset( buf, 0, buf_size );

strcpy( vcap->name, dev->name );
vcap->type = dev->type;

vcap->channels = 1;
vcap->audios = 0;

vcap->maxwidth = 320;
vcap->maxheight = 242;

vcap->minwidth = 320;
vcap->minheight = 242;

break;
case VIDIOCGCHAN:
if ( copy_from_user( vchan, arg, sizeof( *vchan ) ) ) {
err = -EFAULT;
break;
}

if ( vchan->channel ) {
err = -EINVAL;
break;
}

strcpy( vchan->name, dev->name );

vchan->flags = 0;
vchan->tuners = 0;

vchan->type = VIDEO_TYPE_CAMERA;

vchan->norm = 0;

buf_size = sizeof( *vchan );

break;
case VIDIOCSCHAN:
if ( copy_from_user( vchan, arg, sizeof( *vchan ) ) ) {
err = -EFAULT;
break;
}

if ( vchan->channel ) {
err = -EINVAL;
break;
}

break;
case VIDIOCGPICT:
buf_size = sizeof( *vpic );

memset( vpic, 0, buf_size );

vpic->brightness = vicam_v4l_priv->gain << 8;
vpic->depth = 24;
vpic->palette = VIDEO_PALETTE_RGB24;

break;
case VIDIOCSPICT:
if ( copy_from_user( vpic, arg, sizeof( *vpic ) ) ) {
err = -EFAULT;
break;
}

if ( vpic->depth != 24 ||
vpic->palette != VIDEO_PALETTE_RGB24 ) {
err = -EINVAL;
}

vicam_v4l_priv->gain = vpic->brightness >> 8;

break;
case VIDIOCGWIN:
buf_size = sizeof( *vwin );

memset( vwin, 0, buf_size );

vwin->x = 0;
vwin->y = 0;

vwin->width = 320;
vwin->height = vicam_v4l_priv->height;

vwin->chromakey = 0;
vwin->flags = 0;
vwin->clips = NULL;
vwin->clipcount = 0;

break;
case VIDIOCSWIN:
if ( vwin->x != 0 || vwin->y != 0 ) {
err = -EINVAL;
}

if ( vwin->width != 320 ||
vwin->height != vicam_v4l_priv->height ) {
err = -EINVAL;
}

break;
case VIDIOCGMBUF:
buf_size = sizeof( *vmbuf );

memset( vmbuf, 0, buf_size );

vmbuf->frames = min( VICAM_NUM_FRAMES, VIDEO_MAX_FRAME );
vmbuf->size = VICAM_FRAME_SIZE * vmbuf->frames;

for ( i = 0; i < vmbuf->frames; i++ ) {
vmbuf->offsets[i] = VICAM_FRAME_SIZE * i;
}

break;
case VIDIOCMCAPTURE:
if ( copy_from_user( vmmap, arg, sizeof( *vmmap ) ) ) {
err = -EFAULT;
break;
}

if ( vmmap->frame > VICAM_NUM_FRAMES ||
vmmap->format != VIDEO_PALETTE_RGB24 ) {
err = -EINVAL;
break;
}

err = vicam_capture_image( vicam_v4l_priv, vmmap->frame );

break;
case VIDIOCSYNC:
if ( copy_from_user( &i, arg, sizeof( i ) ) ) {
err = -EFAULT;
break;
}

if ( i > VICAM_NUM_FRAMES ) {
err = -EINVAL;
break;
}

err = down_interruptible( &vicam_v4l_priv->decode_mutex[i] );

break;
default:
err = -ENOIOCTLCMD;
break;
}

if ( !err && buf_size ) {
err = copy_to_user( arg, buf, buf_size ) ? -EFAULT : 0;
}

return err;
}

static int vicam_v4l_mmap( struct video_device *dev, const char *addr,
unsigned long size )
{
struct vicam_v4l_data *vicam_v4l_priv = dev->priv;
unsigned long start = ( unsigned long )( addr );
unsigned long pos;

if ( size > VICAM_FRAME_BUF_SIZE ) {
return -EINVAL;
}

pos = ( unsigned long )( vicam_v4l_priv->frame_buf );

while ( size > 0 ) {
unsigned long page = kvirt_to_pa( pos );

if ( remap_page_range( start,
page,
PAGE_SIZE,
PAGE_SHARED ) ){
return -EAGAIN;
}

start += PAGE_SIZE;
pos += PAGE_SIZE;

/* in case size isn't a multiple of PAGE_SIZE */

size -= min( size, PAGE_SIZE );
}

return 0;
}

static int __devinit vicam_v4l_initialize( struct video_device *dev )
{
struct vicam_v4l_data *vicam_v4l_priv;
int err;
int i;

vicam_v4l_priv = kmalloc( sizeof( *vicam_v4l_priv ), GFP_KERNEL );
if ( !vicam_v4l_priv ) {
return -ENOMEM;
}

memset( vicam_v4l_priv, 0, sizeof( *vicam_v4l_priv ) );

err = -ENOMEM;

vicam_v4l_priv->urb = usb_alloc_urb( 0 );
if ( !vicam_v4l_priv->urb ) {
goto done;
}

vicam_v4l_priv->frame_buf = rvmalloc( VICAM_FRAME_BUF_SIZE );
if ( !vicam_v4l_priv->frame_buf ) {
goto done;
}

vicam_v4l_priv->cntrl_buf = kmalloc( VICAM_CNTRL_BUF_SIZE,
GFP_KERNEL );
if ( !vicam_v4l_priv->cntrl_buf ) {
goto done;
}

for ( i = 0; i < VICAM_NUM_FRAMES; i++ ) {
vicam_v4l_priv->input_buf[i] = kmalloc( VICAM_INPUT_SIZE,
GFP_KERNEL );
if ( !vicam_v4l_priv->input_buf[i] ) {
goto done;
}
}

/* the usb_device was passed to us from the vicam_usb_probe
* function through our dev->priv pointer.
*/

vicam_v4l_priv->usb_dev = dev->priv;
dev->priv = vicam_v4l_priv;

tasklet_init( &vicam_v4l_priv->decode,
vicam_bh_handler,
( unsigned long )( vicam_v4l_priv ) );

init_MUTEX( &vicam_v4l_priv->dev_mutex );
init_MUTEX( &vicam_v4l_priv->busy_mutex );

for ( i = 0; i < VICAM_NUM_FRAMES; i++ ) {
init_MUTEX_LOCKED( &vicam_v4l_priv->decode_mutex[i] );
}

vicam_v4l_priv->width = 512;
vicam_v4l_priv->height = 242;
vicam_v4l_priv->speed = shutter_speed;

for ( i = 0, err = 0; setup[i].firmware && !err; i++ ) {
memcpy( vicam_v4l_priv->cntrl_buf,
setup[i].firmware,
setup[i].size );

err = vicam_send_control_msg( vicam_v4l_priv,
VICAM_REQ_VENDOR,
0,
setup[i].size );
}

done:
if ( err ) {
for ( i = 0; i < VICAM_NUM_FRAMES; i++ ) {
if ( vicam_v4l_priv->input_buf[i] ) {
kfree( vicam_v4l_priv->input_buf[i] );
}
}

if ( vicam_v4l_priv->cntrl_buf ) {
kfree( vicam_v4l_priv->cntrl_buf );
}

if ( vicam_v4l_priv->frame_buf ) {
rvfree( vicam_v4l_priv->frame_buf,
VICAM_FRAME_BUF_SIZE );
}

if ( vicam_v4l_priv->urb ) {
usb_free_urb( vicam_v4l_priv->urb );
}

kfree( vicam_v4l_priv );
}

return err;
}

static void * __devinit vicam_usb_probe( struct usb_device *dev,
unsigned int ifnum,
const struct usb_device_id *devid )
{
struct vicam_usb_data *vicam_usb_priv;
const struct usb_interface *usb_iface;
int err;
u8 endpt_addr, endpt_attr;

vicam_usb_priv = NULL;

usb_iface = usb_ifnum_to_if( dev, ifnum );

if ( usb_iface->num_altsetting != 1 ) {
return NULL;
}

endpt_addr = usb_iface->altsetting[0].endpoint[0].bEndpointAddress;
endpt_attr = usb_iface->altsetting[0].endpoint[0].bmAttributes;

if ( !( endpt_addr & USB_ENDPOINT_DIR_MASK ) ||
( endpt_attr & USB_ENDPOINT_XFERTYPE_MASK ) !=
USB_ENDPOINT_XFER_BULK ) {
return NULL;
}

vicam_usb_priv = kmalloc( sizeof( *vicam_usb_priv ), GFP_KERNEL );
if ( !vicam_usb_priv ) {
return NULL;
}

memset( vicam_usb_priv, 0, sizeof( *vicam_usb_priv ) );

usb_string( dev, dev->descriptor.iProduct,
vicam_usb_priv->vicam_v4l_dev.name, 32 );

vicam_usb_priv->vicam_v4l_dev.type = VID_TYPE_CAPTURE;
vicam_usb_priv->vicam_v4l_dev.hardware = 0; /* need own id */

vicam_usb_priv->vicam_v4l_dev.initialize = vicam_v4l_initialize;
vicam_usb_priv->vicam_v4l_dev.open = vicam_v4l_open;
vicam_usb_priv->vicam_v4l_dev.close = vicam_v4l_close;
vicam_usb_priv->vicam_v4l_dev.write = vicam_v4l_write;
vicam_usb_priv->vicam_v4l_dev.ioctl = vicam_v4l_ioctl;
vicam_usb_priv->vicam_v4l_dev.mmap = vicam_v4l_mmap;

vicam_usb_priv->vicam_v4l_dev.owner = THIS_MODULE;

/* we need to get the usb_device struct to the
* vicam_v4l_initialize function [preferably]
* without using globals.
*/

vicam_usb_priv->vicam_v4l_dev.priv = dev;

err = video_register_device ( &vicam_usb_priv->vicam_v4l_dev,
VFL_TYPE_GRABBER, -1 );

if ( err ) {
kfree( vicam_usb_priv );
vicam_usb_priv = NULL;
} else {
struct vicam_v4l_data *vicam_v4l_priv =
vicam_usb_priv->vicam_v4l_dev.priv;

vicam_v4l_priv->bulk_endpoint = endpt_addr;
}

return vicam_usb_priv;
}

static void __devexit vicam_usb_disconnect( struct usb_device *dev, void *data )
{
struct vicam_usb_data *vicam_usb_priv;
struct vicam_v4l_data *vicam_v4l_priv;
int i;

vicam_usb_priv = data;
vicam_v4l_priv = vicam_usb_priv->vicam_v4l_dev.priv;

/* what happens if a disconnect occurs while the device is open? */

video_unregister_device( &vicam_usb_priv->vicam_v4l_dev );

tasklet_kill( &vicam_v4l_priv->decode );

usb_free_urb( vicam_v4l_priv->urb );
rvfree( vicam_v4l_priv->frame_buf, VICAM_FRAME_BUF_SIZE );
kfree( vicam_v4l_priv->cntrl_buf );

for ( i = 0; i < VICAM_NUM_FRAMES; i++ ) {
if ( vicam_v4l_priv->input_buf[i] ) {
kfree( vicam_v4l_priv->input_buf[i] );
}
}

kfree( vicam_v4l_priv );
kfree( vicam_usb_priv );
}

static struct usb_device_id __devinitdata vicam_usb_table[] = {
{ USB_DEVICE( USB_3COMHC_VENDOR_ID, USB_3COMHC_PRODUCT_ID ) },
/* That's all folks */
{ .match_flags = 0 }
};

static struct usb_driver vicam_usb_drv = {
.name = "vicam_usb",
.probe = vicam_usb_probe,
.disconnect = __devexit_p( vicam_usb_disconnect ),
.id_table = vicam_usb_table
};

static int __init vicam_usb_init( void )
{
reverse_rgb = clamp( reverse_rgb, 0, 1 );
shutter_speed = clamp( shutter_speed, 2, 60 );

return usb_register( &vicam_usb_drv );
}

static void __exit vicam_usb_exit( void )
{
usb_deregister( &vicam_usb_drv );
}

module_init( vicam_usb_init );
module_exit( vicam_usb_exit );

MODULE_DEVICE_TABLE( usb, vicam_usb_table );

MODULE_PARM( reverse_rgb, "i" );
MODULE_PARM_DESC( reverse_rgb, "Perform RGB to BGR conversion" );

MODULE_PARM( shutter_speed, "i" );

MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "John Tyner <jtyner@cs.ucr.edu>" );
MODULE_DESCRIPTION( "ViCAM USB/V4L Driver" );
INCLUDE = -I /usr/src/linux/include
DEFINES = -D__KERNEL__ -DMODULE
CFLAGS = -O2 -Wall -Werror

vicam.o: vicam.c vicam.h Makefile
gcc $(CFLAGS) $(INCLUDE) $(DEFINES) -c $< -o $@

clean:
rm -f *.o *~ *#
\
 
 \ /
  Last update: 2005-03-22 13:29    [W:0.064 / U:0.288 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site