[cpia] USB - First Contact (2/2)
Jochen Scharrlach
Jochen.Scharrlach@schwaben.de
Wed, 26 Jan 2000 22:09:03 +0100 (CET)
if(cam->open_count == 0) {
DBG("unregistering video\n");
video_unregister_device(&cam->vdev);
} else {
LOG("/dev/video%d removed while open, "
"deferring video_unregister_device\n", cam->vdev.minor);
+ DBG("camera open -- setting ops to NULL\n");
+ cam->ops = NULL;
}
- /* Need a lock when adding/removing cameras. This doesn't happen
- * often and doesn't take very long, so grabbing the kernel lock
- * should be OK. */
- lock_kernel();
-
#ifdef CONFIG_PROC_FS
DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
destroy_proc_cpia_cam(cam);
#endif
if(cam->open_count == 0) {
DBG("freeing camera\n");
- kfree(camera[camnr]);
- camera[camnr] = NULL;
- } else {
- DBG("camera open -- setting ops to NULL\n");
- cam->ops = NULL;
+ kfree(cam);
}
- unlock_kernel();
}
/****************************************************************************
--- cpia-0.6.0/module/cpia.h Sat Jan 22 18:43:05 2000
+++ cpia-usb/module/cpia.h Sun Jan 23 21:25:04 2000
@@ -26,12 +26,33 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/videodev.h>
+#include <linux/pagemap.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
#define CPIA_MAJ_VER 0
-#define CPIA_MIN_VER 6
+#define CPIA_MIN_VER 5
#define CPIA_PATCH_VER 0
#define CPIA_PP_MAJ_VER 0
-#define CPIA_PP_MIN_VER 6
+#define CPIA_PP_MIN_VER 5
#define CPIA_PP_PATCH_VER 0
#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */
@@ -46,7 +67,7 @@
/* open sets privdata to point to structure for this camera.
* Returns negative value on error, otherwise 0.
*/
- int (*open)(int camnr, void **privdata);
+ int (*open)(void *privdata);
/* Registers callback function cb to be called with cbdata
* when an image is ready. If cb is NULL, only single image grabs
@@ -88,13 +109,184 @@
int (*close)(void *privdata);
};
+struct cpia_frame {
+ u8 *data;
+ int count;
+ int width;
+ int height;
+ volatile int state;
+};
+
+struct cam_params {
+ struct {
+ u8 firmwareVersion;
+ u8 firmwareRevision;
+ u8 vcVersion;
+ u8 vcRevision;
+ } version;
+ struct {
+ u16 vendor;
+ u16 product;
+ u16 deviceRevision;
+ } pnpID;
+ struct {
+ u8 vpVersion;
+ u8 vpRevision;
+ u16 cameraHeadID;
+ } vpVersion;
+ struct {
+ u8 systemState;
+ u8 grabState;
+ u8 streamState;
+ u8 fatalError;
+ u8 cmdError;
+ u8 debugFlags;
+ u8 vpStatus;
+ u8 errorCode;
+ } status;
+ struct {
+ u8 brightness;
+ u8 contrast;
+ u8 saturation;
+ } colourParams;
+ struct {
+ u8 gainMode;
+ u8 expMode;
+ u8 compMode;
+ u8 centreWeight;
+ u8 gain;
+ u8 fineExp;
+ u8 coarseExpLo;
+ u8 coarseExpHi;
+ u8 redComp;
+ u8 green1Comp;
+ u8 green2Comp;
+ u8 blueComp;
+ } exposure;
+ struct {
+ u8 balanceMode;
+ u8 redGain;
+ u8 greenGain;
+ u8 blueGain;
+ } colourBalance;
+ struct {
+ u8 divisor;
+ u8 baserate;
+ } sensorFps;
+ struct {
+ u8 gain1;
+ u8 gain2;
+ u8 gain4;
+ u8 gain8;
+ } apcor;
+ struct {
+ u8 flickerMode;
+ u8 coarseJump;
+ u8 allowableOverExposure;
+ } flickerControl;
+ struct {
+ u8 gain1;
+ u8 gain2;
+ u8 gain4;
+ u8 gain8;
+ } vlOffset;
+ struct {
+ u8 mode;
+ u8 decimation;
+ } compression;
+ struct {
+ u8 frTargeting;
+ u8 targetFR;
+ u8 targetQ;
+ } compressionTarget;
+ struct {
+ u8 yThreshold;
+ u8 uvThreshold;
+ } yuvThreshold;
+ struct {
+ u8 hysteresis;
+ u8 threshMax;
+ u8 smallStep;
+ u8 largeStep;
+ u8 decimationHysteresis;
+ u8 frDiffStepThresh;
+ u8 qDiffStepThresh;
+ u8 decimationThreshMod;
+ } compressionParams;
+ struct {
+ u8 videoSize; /* CIF/QCIF */
+ u8 subSample;
+ u8 yuvOrder;
+ } format;
+ struct {
+ u8 colStart; /* skip first 8*colStart pixels */
+ u8 colEnd; /* finish at 8*colEnd pixels */
+ u8 rowStart; /* skip first 4*rowStart lines */
+ u8 rowEnd; /* finish at 4*rowEnd lines */
+ } roi;
+ u8 ecpTiming;
+ u8 streamStartLine;
+};
+
+enum v4l_camstates {
+ CPIA_V4L_IDLE = 0,
+ CPIA_V4L_ERROR,
+ CPIA_V4L_COMMAND,
+ CPIA_V4L_GRABBING,
+ CPIA_V4L_STREAMING,
+ CPIA_V4L_STREAMING_PAUSED,
+};
+
+#define FRAME_NUM 2 /* double buffering for now */
+
+struct cam_data {
+ struct cam_data **previous;
+ struct cam_data *next;
+
+ struct semaphore busy_lock; /* guard against SMP multithreading */
+ struct cpia_camera_ops *ops; /* lowlevel driver operations */
+ void *lowlevel_data; /* private data for lowlevel driver */
+ u8 *raw_image; /* buffer for raw image data */
+ struct cpia_frame decompressed_frame;
+ /* buffer to hold decompressed frame */
+ int image_size; /* sizeof last decompressed image */
+ int open_count; /* # of process that have camera open */
+
+ /* camera status */
+ int fps; /* actual fps reported by the camera */
+ int transfer_rate; /* transfer rate from camera in kB/s */
+ u8 mainsFreq; /* for flicker control */
+
+ /* proc interface */
+ struct semaphore param_lock; /* params lock for this camera */
+ struct cam_params params; /* camera settings */
+ struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */
+
+ /* v4l */
+ int video_size; /* VIDEO_SIZE_ */
+ volatile enum v4l_camstates camstate; /* v4l layer status */
+ struct video_device vdev; /* v4l videodev */
+ struct video_picture vp; /* v4l camera settings */
+ struct video_window vw; /* v4l capture area */
+
+ /* mmap interface */
+ int curframe; /* the current frame to grab into */
+ u8 *frame_buf; /* frame buffer data */
+ struct cpia_frame frame[FRAME_NUM];
+ /* FRAME_NUM-buffering, so we need a array */
+
+ int first_frame;
+ int mmap_kludge; /* 'wrong' byte order for mmap */
+ volatile u32 cmd_queue; /* queued commands */
+};
+
/* cpia_register_camera is called by low level driver for each camera.
* A unique camera number is returned, or a negative value on error */
-int cpia_register_camera(struct cpia_camera_ops *ops);
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
/* cpia_unregister_camera is called by low level driver when a camera
* is removed. This must not fail. */
-void cpia_unregister_camera(int camnr);
+void cpia_unregister_camera(struct cam_data *cam);
#define CPIA_MAXCAMS 4
@@ -134,7 +326,6 @@
#define DECIMATION_ENAB 1
#define EOI 0xff /* End Of Image */
#define EOL 0xfd /* End Of Line */
-#define FRAME_HEADER_SIZE 64
/* Image grab modes */
#define CPIA_GRAB_SINGLE 0
@@ -216,6 +407,38 @@
DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
(p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
(p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
+
+#define ADD_TO_LIST(l, drv) \
+ {\
+ lock_kernel();\
+ (drv)->next = l;\
+ (drv)->previous = &(l);\
+ (l) = drv;\
+ unlock_kernel();\
+ } while(0)
+
+#define REMOVE_FROM_LIST(drv) \
+ {\
+ if ((drv)->previous != NULL) {\
+ lock_kernel();\
+ if ((drv)->next != NULL)\
+ (drv)->next->previous = (drv)->previous;\
+ *((drv)->previous) = (drv)->next;\
+ (drv)->previous = NULL;\
+ (drv)->next = NULL;\
+ unlock_kernel();\
+ }\
+ } while (0)
+
+#define SEARCH_LIST(l, attr, i, ret) \
+ {\
+ lock_kernel();\
+ for (ret=l; ret != NULL && ret->lowlevel_data->attr != i; \
+ ret = ret->next); /* empty body */ \
+ unlock_kernel();\
+ } while (0)
+
+
#endif /* __KERNEL__ */
--Multipart_Wed_Jan_26_22:09:03_2000-1
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="cpia_usb.c"
Content-Transfer-Encoding: 7bit
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include "cpia.h"
#include "/usr/src/linux/drivers/usb/usb.h"
#define USB_REQ_CPIA_GRAB_FRAME 0xC1
#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
#define WAIT_FOR_NEXT_FRAME 0
#define FORCE_FRAME_UPLOAD 1
#define FRAMES_PER_DESC 10
#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
#define CPIA_NUMSBUF 2
#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
struct cpia_sbuf {
char *data;
urb_t *urb;
};
#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
enum framebuf_status {
FRAME_EMPTY,
FRAME_READING,
FRAME_READY,
};
struct framebuf
{
int length;
enum framebuf_status status;
u8 data[FRAMEBUF_LEN];
struct framebuf *next;
};
struct usb_cpia {
/* Device structure */
struct usb_device *dev;
unsigned char iface;
wait_queue_head_t wq_stream;
int cursbuf; /* Current receiving sbuf */
struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
/* u8 *buffer; */
/* int buffer_length; */
/* int buffer_maxlength; */
/* unsigned char scratch[SCRATCH_BUF_SIZE]; */
/* int scratchlen; */
int streaming;
struct framebuf *buffers[3];
struct framebuf *curbuff, *workbuff;
};
static int cpia_usb_open(void *privdata);
static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
void *cbdata);
static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
static int cpia_usb_streamStart(void *privdata);
static int cpia_usb_streamStop(void *privdata);
static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
static int cpia_usb_close(void *privdata);
#define ABOUT "USB driver for Vision CPiA based cameras"
static struct cpia_camera_ops cpia_usb_ops =
{
cpia_usb_open,
cpia_usb_registerCallback,
cpia_usb_transferCmd,
cpia_usb_streamStart,
cpia_usb_streamStop,
cpia_usb_streamRead,
cpia_usb_close
};
static struct cam_data *cam_list;
static void cpia_usb_complete(struct urb *urb)
{
int i;
char *cdata;
struct usb_cpia *cpia = (struct usb_cpia *) urb->context;
if (cpia->workbuff->status == FRAME_EMPTY)
{
cpia->workbuff->status = FRAME_READING;
cpia->workbuff->length = 0;
}
for (i = 0; i < urb->number_of_packets; i++) {
int n = urb->iso_frame_desc[i].actual_length;
int st = urb->iso_frame_desc[i].status;
cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
if (st)
printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
i, n, st);
if (FRAMEBUF_LEN < cpia->workbuff->length+n) {
printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n",cpia->workbuff->length, n );
return;
}
if (n) {
if (cpia->workbuff->length >0 ||
(0x19 == cdata[0] && 0x68 == cdata[1]))
{
memcpy(cpia->workbuff->data+cpia->workbuff->length, cdata, n);
cpia->workbuff->length += n;
}
else
DBG ("Ignoring packet!\n");
} else {
if (cpia->workbuff->length > 4 &&
0xff == cpia->workbuff->data[cpia->workbuff->length-1] &&
0xff == cpia->workbuff->data[cpia->workbuff->length-2] &&
0xff == cpia->workbuff->data[cpia->workbuff->length-3] &&
0xff == cpia->workbuff->data[cpia->workbuff->length-4])
{
cpia->workbuff->status = FRAME_READY;
cpia->curbuff = cpia->workbuff;
cpia->workbuff = cpia->workbuff->next;
cpia->workbuff->status = FRAME_EMPTY;
cpia->workbuff->length = 0;
if (waitqueue_active(&cpia->wq_stream)) {
wake_up_interruptible(&cpia->wq_stream);
}
}
}
}
}
static int cpia_usb_open(void *privdata)
{
struct usb_cpia *cpia = (struct usb_cpia *) privdata;
urb_t *urb;
int fx, err;
if (cpia == NULL)
return -EINVAL;
cpia->sbuf[0].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!cpia->sbuf[0].data)
return -EINVAL;
cpia->sbuf[1].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!cpia->sbuf[1].data)
{
kfree (cpia->sbuf[0].data);
return -EINVAL;
}
if (usb_set_interface(cpia->dev, cpia->iface, 3) < 0) {
printk(KERN_ERR "usb_set_interface error\n");
kfree (cpia->sbuf[0].data);
kfree (cpia->sbuf[1].data);
return -EBUSY;
}
cpia->buffers[0]->status = FRAME_EMPTY;
cpia->buffers[0]->length = 0;
cpia->buffers[1]->status = FRAME_EMPTY;
cpia->buffers[1]->length = 0;
cpia->buffers[2]->status = FRAME_EMPTY;
cpia->buffers[2]->length = 0;
cpia->curbuff = cpia->buffers[0];
cpia->workbuff = cpia->buffers[1];
/* We double buffer the Iso lists */
// err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC, cpia, &cpia->sbuf[0].isodesc);
urb = usb_alloc_urb(FRAMES_PER_DESC);
if (!urb) {
printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
0);
kfree (cpia->sbuf[0].data);
kfree (cpia->sbuf[1].data);
return -ENOMEM;
}
cpia->sbuf[0].urb = urb;
urb->dev = cpia->dev;
urb->context = cpia;
urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
urb->transfer_flags = USB_ISO_ASAP;
urb->transfer_buffer = cpia->sbuf[0].data;
urb->complete = cpia_usb_complete;
urb->number_of_packets = FRAMES_PER_DESC;
urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
}
urb = usb_alloc_urb(FRAMES_PER_DESC);
if (!urb) {
printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
0);
kfree (cpia->sbuf[0].data);
kfree (cpia->sbuf[1].data);
return -ENOMEM;
}
cpia->sbuf[1].urb = urb;
urb->dev = cpia->dev;
urb->context = cpia;
urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
urb->transfer_flags = USB_ISO_ASAP;
urb->transfer_buffer = cpia->sbuf[1].data;
urb->complete = cpia_usb_complete;
urb->number_of_packets = FRAMES_PER_DESC;
urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
}
cpia->sbuf[1].urb->next = cpia->sbuf[0].urb;
cpia->sbuf[0].urb->next = cpia->sbuf[1].urb;
err = usb_submit_urb(cpia->sbuf[0].urb);
if (err)
printk(KERN_ERR "cpia_init_isoc: usb_run_isoc(0) ret %d\n",
err);
err = usb_submit_urb(cpia->sbuf[1].urb);
if (err)
printk(KERN_ERR "cpia_init_isoc: usb_run_isoc(1) ret %d\n",
err);
cpia->streaming = 1;
return 0;
}
//
// convenience functions
//
/****************************************************************************
*
* WritePacket
*
***************************************************************************/
static int WritePacket(struct usb_device *cam, const u8 *packet)
{
if (packet == NULL) {
return -EINVAL;
}
return usb_control_msg(cam, usb_sndctrlpipe(cam, 0),
packet[1] + (packet[0] << 8),
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
packet[2] + (packet[3] << 8),
packet[4] + (packet[5] << 8), NULL, 0, HZ);
}
/****************************************************************************
*
* ReadPacket
*
***************************************************************************/
static int ReadPacket(struct usb_device *cam, u8 *packet, u8 *buf, size_t size)
{
if (packet == NULL || size <= 0) {
return -EINVAL;
}
return usb_control_msg(cam, usb_rcvctrlpipe(cam, 0),
packet[1] + (packet[0] << 8),
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
packet[2] + (packet[3] << 8),
packet[4] + (packet[5] << 8), buf, size, HZ);
}
static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
{
int err=0;
int databytes;
struct usb_device *cam = ((struct usb_cpia*)privdata)->dev;
if(cam == NULL) {
DBG("Internal driver error: cam is NULL\n");
return -EINVAL;
}
if(command == NULL) {
DBG("Internal driver error: command is NULL\n");
return -EINVAL;
}
databytes = (((int)command[7])<<8) | command[6];
if(command[0] == DATA_IN) {
u8 buffer[8];
if(data == NULL) {
DBG("Internal driver error: data is NULL\n");
return -EINVAL;
}
err = ReadPacket(cam, command, buffer, 8);
if(err < 0) {
return err;
}
memcpy(data, buffer, databytes);
} else if(command[0] == DATA_OUT) {
WritePacket(cam, command);
} else {
DBG("Unexpected first byte of command: %x\n", command[0]);
err = -EINVAL;
}
return 0;
}
static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
void *cbdata)
{
return -ENODEV;
}
static int cpia_usb_streamStart(void *privdata)
{
return -ENODEV;
}
static int cpia_usb_streamStop(void *privdata)
{
return -ENODEV;
}
static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
{
struct usb_cpia *cpia = (struct usb_cpia *) privdata;
struct framebuf *mybuff;
if (cpia->curbuff->status != FRAME_READY) {
interruptible_sleep_on(&cpia->wq_stream);
} else
DBG ("Frame already waiting!\n");
mybuff = cpia->curbuff;
if (mybuff->status != FRAME_READY || mybuff->length < 4) {
DBG ("Something went wrong!\n");
return -1;
}
memcpy (frame, mybuff->data, mybuff->length);
mybuff->status = FRAME_EMPTY;
/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */
/* mybuff->length, frame[0], frame[1], */
/* frame[mybuff->length-4], frame[mybuff->length-3], */
/* frame[mybuff->length-2], frame[mybuff->length-1]); */
return mybuff->length;
}
static int cpia_usb_close(void *privdata)
{
struct usb_cpia *cpia = (struct usb_cpia *) privdata;
if (!cpia->streaming)
return 0;
/* Set packet size to 0 */
if (usb_set_interface(cpia->dev, cpia->iface, 0) < 0) {
printk(KERN_ERR "usb_set_interface error\n");
return -EINVAL;
}
/* Unschedule all of the iso td's */
usb_unlink_urb(cpia->sbuf[1].urb);
usb_unlink_urb(cpia->sbuf[0].urb);
cpia->streaming = 0;
/* Delete them all */
usb_free_urb(cpia->sbuf[1].urb);
usb_free_urb(cpia->sbuf[0].urb);
return 0;
}
int cpia_usb_init(void)
{
/* return -ENODEV; */
return 0;
}
//
// Probing and initializing
//
static void * cpia_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
struct usb_cpia *cpia;
struct cam_data *cam;
/* We don't handle multi-config cameras */
if (dev->descriptor.bNumConfigurations != 1)
return NULL;
interface = &dev->actconfig->interface[ifnum].altsetting[0];
/* Is it a CPiA? */
if (dev->descriptor.idVendor != 0x0553)
return NULL;
if (dev->descriptor.idProduct != 0x0002)
return NULL;
/* Checking vendor/product should be enough, but what the hell */
if (interface->bInterfaceClass != 0xFF)
return NULL;
if (interface->bInterfaceSubClass != 0x00)
return NULL;
/* We found a CPiA */
printk(KERN_INFO "USB CPiA camera found\n");
if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "couldn't kmalloc cpia struct\n");
return NULL;
}
memset(cpia, 0, sizeof(*cpia));
cpia->dev = dev;
cpia->iface = interface->bInterfaceNumber;
init_waitqueue_head(&cpia->wq_stream);
cpia->buffers[0] = vmalloc(sizeof(struct framebuf));
cpia->buffers[1] = vmalloc(sizeof(struct framebuf));
cpia->buffers[2] = vmalloc(sizeof(struct framebuf));
if (cpia->buffers[0] == NULL ||
cpia->buffers[1] == NULL ||
cpia->buffers[2] == NULL)
{
printk(KERN_ERR "couldn't kmalloc frame buffers\n");
return NULL;
}
cpia->buffers[0]->next = cpia->buffers[1];
cpia->buffers[1]->next = cpia->buffers[2];
cpia->buffers[2]->next = cpia->buffers[0];
if (usb_set_interface(dev, interface->bInterfaceNumber, 0) < 0) {
printk(KERN_ERR "usb_set_interface error\n");
return NULL;
}
if((cam=cpia_register_camera(&cpia_usb_ops, cpia))==NULL) {
LOG("failed to cpia_register_camera\n");
return NULL;
}
ADD_TO_LIST(cam_list, cam);
return cam;
}
static void cpia_disconnect(struct usb_device *dev, void *ptr);
static struct usb_driver cpia_driver = {
"cpia",
cpia_probe,
cpia_disconnect,
{ NULL, NULL }
};
/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */
static void cpia_disconnect(struct usb_device *dev, void *ptr)
{
struct cam_data *cpia = (struct cam_data *) ptr;
struct usb_cpia *cam = (struct usb_cpia *) cpia->lowlevel_data;
REMOVE_FROM_LIST(cpia);
cpia_unregister_camera(cpia);
usb_driver_release_interface(&cpia_driver,
&cam->dev->actconfig->interface[0]);
/* Free the memory */
kfree(cam);
}
int usb_cpia_init(void)
{
cam_list = NULL;
return usb_register(&cpia_driver);
}
void usb_cpia_cleanup(void)
{
struct cam_data *cam;
while((cam = cam_list) != NULL)
cpia_disconnect(NULL, cam);
usb_deregister(&cpia_driver);
}
#ifdef MODULE
int init_module(void)
{
return usb_cpia_init();
}
void cleanup_module(void)
{
usb_cpia_cleanup();
}
#else /* !MODULE */
__initfunc(void cpia_usb_setup(char *str, int *ints))
{
}
#endif /* !MODULE */
--Multipart_Wed_Jan_26_22:09:03_2000-1--