[cpia] USB anyone?

Jochen Scharrlach Jochen.Scharrlach@schwaben.de
Sun, 16 Jan 2000 22:18:55 +0100 (CET)


--Multipart_Sun_Jan_16_22:18:55_2000-1
Content-Type: text/plain; charset=US-ASCII

Peter Pregler writes:
 > That is fine with me as long as it does not blur the destinction between cpia.c
 > and cpia_XXX.c. I don't mind where internal structures are connected to. Can
 > you show me some code?

My idea is to add an argument to cpia_register_camera(), so I can
stuff the driver-struct into the video_device->lowlevel much
sooner. What I am missing is a cpia_unregister_camera()!

I have added my first try on cpia_usb.c, so you can take a look at
it. DISCLAIMER: I am 99.999% sure that it won't even compile, it's
just the result of two Sunday afternoons of hacking. The hard job will
be to get it to work - I am not even sure if the logic is correct, the
USB-stack isn't very well documented :-/

Bye,
Jochen

-- 
new signature coming RSN (tm)


--Multipart_Sun_Jan_16_22:18:55_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/cpia.h>

static int cpia_usb_open(int camnr, 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
};

struct cpia_sbuf {
  char *data;
  urb_t *urb;
};

struct usb_cpia {
  /* Device structure */
  struct usb_device *dev;

  unsigned char iface;
  struct wait_queue *wq_stream;
};

static int cpia_usb_open(int camnr, usb_cpia **privdata)
{
  usb_cpia *cpia = NULL;
  
  if (privdata == NULL)
    return -EINVAL;
  cpia = *privdata;
  if (cpia == NULL)
    return -EINVAL;

  if (usb_set_interface(cpia->dev, cpia->iface, 3) < 0) {
    printk(KERN_ERR "usb_set_interface error\n");
    return -EBUSY;
  }

  return 0;
}

static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
{
  int err;
  int retval=0;
  int databytes;
  struct usb_device *cam = ((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]);
  retval = -EINVAL;
}
return retval;
}

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(usb_cpia *cpia, u8 *frame, int noblock)
{
  int len = 0;
  struct urb *urb = usb_alloc_urb(1);
  
  if (!urb) {
    printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
	   0);
    return -ENOMEM;
  }
  
  FILL_BULK_URB(urb, cpia->dev, usb_rcvbulkpipe(cpia->dev, 1),
		frame, CPIA_MAX_IMAGE_SIZE, cpia_usb_complete, cpia);

  err = usb_submit_urb(urb);
  if (err)
    {
      printk(KERN_ERR "cpia_init_isoc: usb_run_isoc(0) ret %d\n",
	     err);
      return err;
    }
  
  interruptible_sleep_on(&cpia->wq_stream);

  len = urb->actual_length;
  
  usb_unlink_urb(urb);
  usb_free_urb(urb);
  
  return len;
}

static int cpia_usb_close(void *privdata)
{
  return 0;
}

int cpia_usb_init(void)
{
  /*   return -ENODEV; */
  return 0;
}

static void cpia_usb_complete(usb_cpia *cpia)
{
  if (waitqueue_active(&cpia->wq_stream)) { /* FIXME */
    wake_up(&cpia->wq_stream);
  }
}

//
// convenience functions
//

/****************************************************************************
 *
 *  WritePacket
 *
 ***************************************************************************/
static int WritePacket(struct usb_device *cam, const u8 *packet)
{
  if (packet == NULL) {
    return -EINVAL;
  }

  return usb_control_msg(cpia->dev, usb_sndctrlpipe(cpia->dev, 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(cpia->dev, usb_rcvctrlpipe(cpia->dev, 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);
}

//
// Probing and initializing
//

static void * cpia_probe(struct usb_device *dev, unsigned int ifnum)
{
  struct usb_interface_descriptor *interface;
  struct usb_cpia *cpia;

  /* 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(&cpia->wq_stream);
  
  if (usb_set_interface(dev, iface, 0) < 0) {
    printk(KERN_ERR "usb_set_interface error\n");
    return NULL;
  }

  if(cpia_register_camera(&cpia_usb_ops, cpia)<0) {
    LOG("failed to cpia_register_camera\n");
    return NULL;
  }

  return cpia;
}

static void cpia_disconnect(struct usb_device *dev, void *ptr)
{
  struct usb_cpia *cpia = (struct usb_cpia *) ptr;

  // cpia_unregister_camera(cpia);

  usb_driver_release_interface(&cpia_driver,
			       &cpia->dev->actconfig->interface[0]);

  /* Free the memory */
  kfree(cpia);
}

static struct usb_driver cpia_driver = {
  "cpia",
  cpia_probe,
  cpia_disconnect,
  { NULL, NULL }
};

int usb_cpia_init(void)
{
  return usb_register(&cpia_driver);
}

void usb_cpia_cleanup(void)
{
  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_Sun_Jan_16_22:18:55_2000-1--