Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  m5602_core.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
 /*
 * USB Driver for ALi m5602 based webcams
 *
 * Copyright (C) 2008 Erik Andrén
 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
 *
 * Portions of code to USB interface and ALi driver software,
 * Copyright (c) 2006 Willem Duinker
 * v4l2 interface modeled after the V4L2 driver
 * for SN9C10x PC Camera Controllers
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include "m5602_ov9650.h"
#include "m5602_ov7660.h"
#include "m5602_mt9m111.h"
#include "m5602_po1030.h"
#include "m5602_s5k83a.h"
#include "m5602_s5k4aa.h"

/* Kernel module parameters */
int force_sensor;
static bool dump_bridge;
bool dump_sensor;

static const struct usb_device_id m5602_table[] = {
 {USB_DEVICE(0x0402, 0x5602)},
 {}
};

MODULE_DEVICE_TABLE(usb, m5602_table);

/* A skeleton used for sending messages to the sensor */
static const unsigned char sensor_urb_skeleton[] = {
 0x23, M5602_XB_GPIO_EN_H, 0x81, 0x06,
 0x23, M5602_XB_MISC_CTRL, 0x81, 0x80,
 0x13, M5602_XB_I2C_DEV_ADDR, 0x81, 0x00,
 0x13, M5602_XB_I2C_REG_ADDR, 0x81, 0x00,
 0x13, M5602_XB_I2C_DATA, 0x81, 0x00,
 0x13, M5602_XB_I2C_CTRL, 0x81, 0x11
};

/* A skeleton used for sending messages to the m5602 bridge */
static const unsigned char bridge_urb_skeleton[] = {
 0x13, 0x00, 0x81, 0x00
};

/* Reads a byte from the m5602 */
int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
{
 int err;
 struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
 struct usb_device *udev = sd->gspca_dev.dev;
 __u8 *buf = sd->gspca_dev.usb_buf;

 err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
         0x04, 0xc0, 0x14,
         0x8100 + address, buf,
         1, M5602_URB_MSG_TIMEOUT);
 *i2c_data = buf[0];

 gspca_dbg(gspca_dev, D_CONF, "Reading bridge register 0x%x containing 0x%x\n",
    address, *i2c_data);

 /* usb_control_msg(...) returns the number of bytes sent upon success,
mask that and return zero instead*/

 return (err < 0) ? err : 0;
}

/* Writes a byte to the m5602 */
int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
{
 int err;
 struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
 struct usb_device *udev = sd->gspca_dev.dev;
 __u8 *buf = sd->gspca_dev.usb_buf;

 gspca_dbg(gspca_dev, D_CONF, "Writing bridge register 0x%x with 0x%x\n",
    address, i2c_data);

 memcpy(buf, bridge_urb_skeleton,
        sizeof(bridge_urb_skeleton));
 buf[1] = address;
 buf[3] = i2c_data;

 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
    0x04, 0x40, 0x19,
    0x0000, buf,
    4, M5602_URB_MSG_TIMEOUT);

 /* usb_control_msg(...) returns the number of bytes sent upon success,
   mask that and return zero instead */

 return (err < 0) ? err : 0;
}

static int m5602_wait_for_i2c(struct sd *sd)
{
 int err;
 u8 data;

 do {
  err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data);
 } while ((data & I2C_BUSY) && !err);
 return err;
}

int m5602_read_sensor(struct sd *sd, const u8 address,
         u8 *i2c_data, const u8 len)
{
 int err, i;
 struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;

 if (!len || len > sd->sensor->i2c_regW)
  return -EINVAL;

 err = m5602_wait_for_i2c(sd);
 if (err < 0)
  return err;

 err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
     sd->sensor->i2c_slave_id);
 if (err < 0)
  return err;

 err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
 if (err < 0)
  return err;

 /* Sensors with registers that are of only
   one byte width are differently read */


 /* FIXME: This works with the ov9650, but has issues with the po1030 */
 if (sd->sensor->i2c_regW == 1) {
  err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1);
  if (err < 0)
   return err;

  err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
 } else {
  err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
 }

 for (i = 0; (i < len) && !err; i++) {
  err = m5602_wait_for_i2c(sd);
  if (err < 0)
   return err;

  err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));

  gspca_dbg(gspca_dev, D_CONF, "Reading sensor register 0x%x containing 0x%x\n",
     address, *i2c_data);
 }
 return err;
}

int m5602_write_sensor(struct sd *sd, const u8 address,
   u8 *i2c_data, const u8 len)
{
 int err, i;
 u8 *p;
 struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
 struct usb_device *udev = sd->gspca_dev.dev;
 __u8 *buf = sd->gspca_dev.usb_buf;

 /* No sensor with a data width larger than 16 bits has yet been seen */
 if (len > sd->sensor->i2c_regW || !len)
  return -EINVAL;

 memcpy(buf, sensor_urb_skeleton,
        sizeof(sensor_urb_skeleton));

 buf[11] = sd->sensor->i2c_slave_id;
 buf[15] = address;

 /* Special case larger sensor writes */
 p = buf + 16;

 /* Copy a four byte write sequence for each byte to be written to */
 for (i = 0; i < len; i++) {
  memcpy(p, sensor_urb_skeleton + 16, 4);
  p[3] = i2c_data[i];
  p += 4;
  gspca_dbg(gspca_dev, D_CONF, "Writing sensor register 0x%x with 0x%x\n",
     address, i2c_data[i]);
 }

 /* Copy the tailer */
 memcpy(p, sensor_urb_skeleton + 20, 4);

 /* Set the total length */
 p[3] = 0x10 + len;

 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
         0x04, 0x40, 0x19,
         0x0000, buf,
         20 + len * 4, M5602_URB_MSG_TIMEOUT);

 return (err < 0) ? err : 0;
}

/* Dump all the registers of the m5602 bridge,
   unfortunately this breaks the camera until it's power cycled */

static void m5602_dump_bridge(struct sd *sd)
{
 int i;
 for (i = 0; i < 0x80; i++) {
  unsigned char val = 0;
  m5602_read_bridge(sd, i, &val);
  pr_info("ALi m5602 address 0x%x contains 0x%x\n", i, val);
 }
 pr_info("Warning: The ALi m5602 webcam probably won't work until it's power cycled\n");
}

static int m5602_probe_sensor(struct sd *sd)
{
 /* Try the po1030 */
 sd->sensor = &po1030;
 if (!sd->sensor->probe(sd))
  return 0;

 /* Try the mt9m111 sensor */
 sd->sensor = &mt9m111;
 if (!sd->sensor->probe(sd))
  return 0;

 /* Try the s5k4aa */
 sd->sensor = &s5k4aa;
 if (!sd->sensor->probe(sd))
  return 0;

 /* Try the ov9650 */
 sd->sensor = &ov9650;
 if (!sd->sensor->probe(sd))
  return 0;

 /* Try the ov7660 */
 sd->sensor = &ov7660;
 if (!sd->sensor->probe(sd))
  return 0;

 /* Try the s5k83a */
 sd->sensor = &s5k83a;
 if (!sd->sensor->probe(sd))
  return 0;

 /* More sensor probe function goes here */
 pr_info("Failed to find a sensor\n");
 sd->sensor = NULL;
 return -ENODEV;
}

static int m5602_configure(struct gspca_dev *gspca_dev,
      const struct usb_device_id *id);

static int m5602_init(struct gspca_dev *gspca_dev)
{
 struct sd *sd = (struct sd *) gspca_dev;
 int err;

 gspca_dbg(gspca_dev, D_CONF, "Initializing ALi m5602 webcam\n");
 /* Run the init sequence */
 err = sd->sensor->init(sd);

 return err;
}

static int m5602_init_controls(struct gspca_dev *gspca_dev)
{
 struct sd *sd = (struct sd *) gspca_dev;

 if (!sd->sensor->init_controls)
  return 0;

 return sd->sensor->init_controls(sd);
}

static int m5602_start_transfer(struct gspca_dev *gspca_dev)
{
 struct sd *sd = (struct sd *) gspca_dev;
 __u8 *buf = sd->gspca_dev.usb_buf;
 int err;

 /* Send start command to the camera */
 const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};

 if (sd->sensor->start)
  sd->sensor->start(sd);

 memcpy(buf, buffer, sizeof(buffer));
 err = usb_control_msg(gspca_dev->dev,
         usb_sndctrlpipe(gspca_dev->dev, 0),
         0x04, 0x40, 0x19, 0x0000, buf,
         sizeof(buffer), M5602_URB_MSG_TIMEOUT);

 gspca_dbg(gspca_dev, D_STREAM, "Transfer started\n");
 return (err < 0) ? err : 0;
}

static void m5602_urb_complete(struct gspca_dev *gspca_dev,
    u8 *data, int len)
{
 struct sd *sd = (struct sd *) gspca_dev;

 if (len < 6) {
  gspca_dbg(gspca_dev, D_PACK, "Packet is less than 6 bytes\n");
  return;
 }

 /* Frame delimiter: ff xx xx xx ff ff */
 if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff &&
     data[2] != sd->frame_id) {
  gspca_dbg(gspca_dev, D_FRAM, "Frame delimiter detected\n");
  sd->frame_id = data[2];

  /* Remove the extra fluff appended on each header */
  data += 6;
  len -= 6;

  /* Complete the last frame (if any) */
  gspca_frame_add(gspca_dev, LAST_PACKET,
    NULL, 0);
  sd->frame_count++;

  /* Create a new frame */
  gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);

  gspca_dbg(gspca_dev, D_FRAM, "Starting new frame %d\n",
     sd->frame_count);

 } else {
  int cur_frame_len;

  cur_frame_len = gspca_dev->image_len;
  /* Remove urb header */
  data += 4;
  len -= 4;

  if (cur_frame_len + len <= gspca_dev->pixfmt.sizeimage) {
   gspca_dbg(gspca_dev, D_FRAM, "Continuing frame %d copying %d bytes\n",
      sd->frame_count, len);

   gspca_frame_add(gspca_dev, INTER_PACKET,
     data, len);
  } else {
   /* Add the remaining data up to frame size */
   gspca_frame_add(gspca_dev, INTER_PACKET, data,
    gspca_dev->pixfmt.sizeimage - cur_frame_len);
  }
 }
}

static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
{
 struct sd *sd = (struct sd *) gspca_dev;

 /* Run the sensor specific end transfer sequence */
 if (sd->sensor->stop)
  sd->sensor->stop(sd);
}

/* sub-driver description */
static const struct sd_desc sd_desc = {
 .name  = MODULE_NAME,
 .config  = m5602_configure,
 .init  = m5602_init,
 .init_controls = m5602_init_controls,
 .start  = m5602_start_transfer,
 .stopN  = m5602_stop_transfer,
 .pkt_scan = m5602_urb_complete
};

/* this function is called at probe time */
static int m5602_configure(struct gspca_dev *gspca_dev,
      const struct usb_device_id *id)
{
 struct sd *sd = (struct sd *) gspca_dev;
 struct cam *cam;
 int err;

 cam = &gspca_dev->cam;

 if (dump_bridge)
  m5602_dump_bridge(sd);

 /* Probe sensor */
 err = m5602_probe_sensor(sd);
 if (err)
  goto fail;

 return 0;

fail:
 gspca_err(gspca_dev, "ALi m5602 webcam failed\n");
 cam->cam_mode = NULL;
 cam->nmodes = 0;

 return err;
}

static int m5602_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 void m5602_disconnect(struct usb_interface *intf)
{
 struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
 struct sd *sd = (struct sd *) gspca_dev;

 if (sd->sensor->disconnect)
  sd->sensor->disconnect(sd);

 gspca_disconnect(intf);
}

static struct usb_driver sd_driver = {
 .name = MODULE_NAME,
 .id_table = m5602_table,
 .probe = m5602_probe,
#ifdef CONFIG_PM
 .suspend = gspca_suspend,
 .resume = gspca_resume,
 .reset_resume = gspca_resume,
#endif
 .disconnect = m5602_disconnect
};

module_usb_driver(sd_driver);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
module_param(force_sensor, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(force_sensor,
  "forces detection of a sensor, 1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030, 6 = OV7660");

module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");

module_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers at startup providing a sensor is found");

Messung V0.5
C=93 H=94 G=93

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge