Hi Ezequiel, a few minor comments below... On 06/23/2012 08:36 PM, Ezequiel Garcia wrote: > This driver adds support for stk1160 usb bridge as used in some > video/audio usb capture devices. > It is a complete rewrite of staging/media/easycap driver and > it's expected as a future replacement. > > Signed-off-by: Ezequiel Garcia<elezegarcia@xxxxxxxxx> > --- [...] > +/* > + * Read/Write stk registers > + */ > +int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value) > +{ > + int ret; > + > + *value = 0; > + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), > + 0x00, > + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, > + 0x00, > + reg, > + value, > + sizeof(u8), > + HZ); A bit strange indentation, but it's up to you to keep it or not. > + if (ret< 0) { > + stk1160_err("read failed on reg 0x%x (%d)\n", > + reg, ret); > + return ret; > + } > + > + return 0; > +} > + > +int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value) > +{ > + int ret; > + > + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), > + 0x01, > + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, > + value, > + reg, > + NULL, > + 0, > + HZ); > + if (ret< 0) { > + stk1160_err("write failed on reg 0x%x (%d)\n", > + reg, ret); > + return ret; > + } > + > + return 0; > +} > + > +/* TODO: We should break this into pieces */ > +static void stk1160_reg_reset(struct stk1160 *dev) > +{ > + int i; > + > + static struct regval ctl[] = { static const struct regval... ? > + {STK1160_GCTRL+2, 0x0078}, > + > + {STK1160_RMCTL+1, 0x0000}, > + {STK1160_RMCTL+3, 0x0002}, > + > + {STK1160_PLLSO, 0x0010}, > + {STK1160_PLLSO+1, 0x0000}, > + {STK1160_PLLSO+2, 0x0014}, > + {STK1160_PLLSO+3, 0x000E}, > + > + {STK1160_PLLFD, 0x0046}, > + > + /* Timing generator setup */ > + {STK1160_TIGEN, 0x0012}, > + {STK1160_TICTL, 0x002D}, > + {STK1160_TICTL+1, 0x0001}, > + {STK1160_TICTL+2, 0x0000}, > + {STK1160_TICTL+3, 0x0000}, > + {STK1160_TIGEN, 0x0080}, > + > + {0xffff, 0xffff} > + }; > + > + for (i = 0; ctl[i].reg != 0xffff; i++) > + stk1160_write_reg(dev, ctl[i].reg, ctl[i].val); > + > + /* Set selected input from module parameter */ > + switch (dev->ctl_input) { > + case 0: > + stk1160_write_reg(dev, STK1160_GCTRL, 0x98); > + break; > + case 1: > + stk1160_write_reg(dev, STK1160_GCTRL, 0x90); > + break; > + case 2: > + stk1160_write_reg(dev, STK1160_GCTRL, 0x88); > + break; > + case 3: > + stk1160_write_reg(dev, STK1160_GCTRL, 0x80); > + break; How about doing something like: static const u8 gctrl[] = { 0x98, 0x90, 0x88, 0x80 }; if (dev->ctl_input < ARRAY_SIZE(gctrl)) stk1160_write_reg(dev, STK1160_GCTRL, gctrl[dev->ctl_input]); ? > + } > +} > + ... > +static int stk1160_i2c_write_reg(struct stk1160 *dev, u8 addr, > + u8 reg, u8 value) > +{ > + int rc, timeout; > + u8 flag; > + > + /* Set serial device address */ > + rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); > + if (rc< 0) > + return rc; > + > + /* Set i2c device register sub-address */ > + rc = stk1160_write_reg(dev, STK1160_SBUSW_WA, reg); > + if (rc< 0) > + return rc; > + > + /* Set i2c device register value */ > + rc = stk1160_write_reg(dev, STK1160_SBUSW_WD, value); > + if (rc< 0) > + return rc; > + > + /* Start write now */ > + rc = stk1160_write_reg(dev, STK1160_SICTL, 0x01); > + if (rc< 0) > + return rc; > + > + /* Wait until Write Finish bit is set */ > + for (timeout = 100; timeout> 0; > + timeout -= 20) { > + stk1160_read_reg(dev, STK1160_SICTL+1,&flag); > + /* write done? */ > + if (flag& 0x04) > + break; > + > + msleep(20); > + } A bit strange loop, perhaps it's worth to rework it as following: unsigned long end = jiffies + msecs_to_jiffies(timeout); while (time_is_after_jiffies(end)) { ... usleep_range(...); } to better control the actual time spent on busy waiting. You may also want to create a separate function i.e. stk1160_i2c_busy_wait(struct stk1160 *dev, u8 wait_bit_mask, unsigned int timeout) and use to avoid repeating similar pattern. > + > + if (timeout == 0) > + /* return EBUSY, or EFAULT, or what ? */ -ETIMEDOUT ? > + return -EIO; > + > + return 0; > +} > + > +static int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr, > + u8 reg, u8 *value) > +{ > + int rc, timeout; > + u8 flag; > + > + /* Set serial device address */ > + rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); > + if (rc< 0) > + return rc; > + > + /* Set i2c device register sub-address */ > + rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, reg); > + if (rc< 0) > + return rc; > + > + /* Start read now */ > + rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20); > + if (rc< 0) > + return rc; > + > + /* Wait until Read Finish bit is set */ > + for (timeout = 100; timeout> 0; > + timeout -= 20) { > + stk1160_read_reg(dev, STK1160_SICTL+1,&flag); > + /* read done? */ > + if (flag& 0x01) > + break; > + > + msleep(20); > + } > + > + if (timeout == 0) > + /* return EBUSY, or EFAULT, or what ? */ > + return -EIO; > + > + stk1160_read_reg(dev, STK1160_SBUSR_RD, value); > + if (rc< 0) > + return rc; > + > + return 0; > +} > + > +/* > + * stk1160_i2c_check_for_device() > + * check if there is a i2c_device at the supplied address > + */ > +static int stk1160_i2c_check_for_device(struct stk1160 *dev, > + unsigned char addr) > +{ > + int rc, write_timeout; > + u8 flag; > + > + /* Set serial device address */ > + rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); > + if (rc< 0) > + return rc; > + > + /* Set device sub-address, we'll chip version reg */ > + rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, 0x00); > + if (rc< 0) > + return rc; > + > + /* Start read now */ > + rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20); > + if (rc< 0) > + return rc; > + > + /* Wait until Read Finish bit is set */ > + for (write_timeout = 40; write_timeout> 0; > + write_timeout -= 20) { > + stk1160_read_reg(dev, STK1160_SICTL+1,&flag); > + if (flag& 0x01) > + return 0; > + > + msleep(20); > + } > + > + return -ENODEV; > +} > + ... > + > +/* GPIO Control */ > +#define STK1160_GCTRL 0x000 > + > +/* Remote Wakup Control */ > +#define STK1160_RMCTL 0x00C Care to use lower case for all hex numbers ? > + > +/* > + * Decoder Control Register: > + * This byte controls capture start/stop > + * with bit #7 (0x?? OR 0x80 to activate). > + */ > +#define STK1160_DCTRL 0x100 > + > +/* Capture Frame Start Position */ > +#define STK116_CFSPO 0x110 > +#define STK116_CFSPO_STX_L 0x110 > +#define STK116_CFSPO_STX_H 0x111 > +#define STK116_CFSPO_STY_L 0x112 > +#define STK116_CFSPO_STY_H 0x113 > + > +/* Capture Frame End Position */ > +#define STK116_CFEPO 0x114 > +#define STK116_CFEPO_ENX_L 0x114 > +#define STK116_CFEPO_ENX_H 0x115 > +#define STK116_CFEPO_ENY_L 0x116 > +#define STK116_CFEPO_ENY_H 0x117 > + > +/* Serial Interface Control */ > +#define STK1160_SICTL 0x200 > +#define STK1160_SICTL_CD 0x202 > +#define STK1160_SICTL_SDA 0x203 > + > +/* Serial Bus Write */ > +#define STK1160_SBUSW 0x204 > +#define STK1160_SBUSW_WA 0x204 > +#define STK1160_SBUSW_WD 0x205 > + > +/* Serial Bus Read */ > +#define STK1160_SBUSR 0x208 > +#define STK1160_SBUSR_RA 0x208 > +#define STK1160_SBUSR_RD 0x209 > + > +/* Alternate Serial Inteface Control */ > +#define STK1160_ASIC 0x2FC > + > +/* PLL Select Options */ > +#define STK1160_PLLSO 0x018 > + > +/* PLL Frequency Divider */ > +#define STK1160_PLLFD 0x01C > + > +/* Timing Generator */ > +#define STK1160_TIGEN 0x300 > + > +/* Timing Control Parameter */ > +#define STK1160_TICTL 0x350 > + > +/* AC97 Audio Control */ > +#define STK1160_AC97CTL_0 0x500 > +#define STK1160_AC97CTL_1 0x504 > + > +/* Use [0:6] bits of register 0x504 to set codec command address */ > +#define STK1160_AC97_ADDR 0x504 > +/* Use [16:31] bits of register 0x500 to set codec command data */ > +#define STK1160_AC97_CMD 0x502 > + > +/* Audio I2S Interface */ > +#define STK1160_I2SCTL 0x50c > + > +/* EEPROM Interface */ > +#define STK1160_EEPROM_SZ 0x5f0 ... > +static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) > +{ > + struct stk1160 *dev = video_drvdata(file); > + int rc; > + > + if (!stk1160_is_owner(dev, file)) > + return -EBUSY; > + > + rc = vb2_querybuf(&dev->vb_vidq, p); > + > + return rc; What about dropping the local "rc" variable here ? > +} > + > +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) > +{ > + struct stk1160 *dev = video_drvdata(file); > + int rc; > + > + if (!stk1160_is_owner(dev, file)) > + return -EBUSY; > + > + rc = vb2_qbuf(&dev->vb_vidq, p); > + > + return rc; Ditto. > +} > + > +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) > +{ > + struct stk1160 *dev = video_drvdata(file); > + int rc; > + > + if (!stk1160_is_owner(dev, file)) > + return -EBUSY; > + > + rc = vb2_dqbuf(&dev->vb_vidq, p, file->f_flags& O_NONBLOCK); > + > + return rc; Ditto. > +} > + > +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) > +{ > + struct stk1160 *dev = video_drvdata(file); > + int rc; > + > + if (!stk1160_is_owner(dev, file)) > + return -EBUSY; > + > + rc = vb2_streamon(&dev->vb_vidq, i); > + > + return rc; Ditto. > +} > + > +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) > +{ > + struct stk1160 *dev = video_drvdata(file); > + int rc; > + > + if (!stk1160_is_owner(dev, file)) > + return -EBUSY; > + > + rc = vb2_streamoff(&dev->vb_vidq, i); > + > + return rc; Ditto. > +} > + > +/* > + * vidioc ioctls > + */ ... > +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) > +{ > + struct stk1160 *dev = video_drvdata(file); > + > + if (!stk1160_acquire_owner(dev, file)) > + return -EBUSY; > + > + if (i> STK1160_MAX_INPUT) > + return -EINVAL; > + > + dev->ctl_input = i; > + > + switch (dev->ctl_input) { > + case 0: > + stk1160_write_reg(dev, STK1160_GCTRL, 0x98); > + break; > + case 1: > + stk1160_write_reg(dev, STK1160_GCTRL, 0x90); > + break; > + case 2: > + stk1160_write_reg(dev, STK1160_GCTRL, 0x88); > + break; > + case 3: > + stk1160_write_reg(dev, STK1160_GCTRL, 0x80); > + break; > + } Same block of code as in stk1160_reg_reset(). Probably it's worth to move it into separate function. > + > + return 0; > +} > + ... > +/* > + * Videobuf2 operations > + */ > +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *v4l_fmt, > + unsigned int *nbuffers, unsigned int *nplanes, > + unsigned int sizes[], void *alloc_ctxs[]) > +{ > + struct stk1160 *dev = vb2_get_drv_priv(vq); > + unsigned long size; > + > + size = dev->width * dev->height * 2; > + > + /* > + * Here we can change the number of buffers being requested. > + * So, we set a minimum and a maximum like this: > + */ > + *nbuffers = clamp_t(unsigned int, *nbuffers, > + STK1160_MIN_VIDEO_BUFFERS, STK1160_MAX_VIDEO_BUFFERS); > + > + /* This means a packed colorformat */ > + *nplanes = 1; > + > + sizes[0] = size; > + > + stk1160_info("%s: buffer count %d, each %ld bytes\n", > + __func__, *nbuffers, size); > + > + return 0; > +} > + > +static void buffer_queue(struct vb2_buffer *vb) > +{ > + unsigned long flags = 0; No need to initialize here. > + struct stk1160 *dev = vb2_get_drv_priv(vb->vb2_queue); > + struct stk1160_buffer *buf = > + container_of(vb, struct stk1160_buffer, vb); > + > + spin_lock_irqsave(&dev->buf_lock, flags); > + if (!dev->udev) { > + /* > + * If the device is disconnected return the buffer to userspace > + * directly. The next QBUF call will fail with -ENODEV. > + */ > + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); > + } else { > + > + buf->mem = vb2_plane_vaddr(vb, 0); > + buf->length = vb2_plane_size(vb, 0); > + buf->bytesused = 0; > + buf->pos = 0; > + > + /* > + * If buffer length is different from expected then we return > + * the buffer to userspace directly. > + */ > + if (buf->length != dev->width * dev->height * 2) It should be OK when the buffer size is larger than the amount of data the device will be writing to it. So it's better to change the condition statement to: if (buf->length < dev->width * dev->height * 2) > + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); > + else > + list_add_tail(&buf->list,&dev->avail_bufs); > + > + } > + spin_unlock_irqrestore(&dev->buf_lock, flags); > +} > + > +static int start_streaming(struct vb2_queue *vq, unsigned int count) > +{ > + struct stk1160 *dev = vb2_get_drv_priv(vq); > + int rc; Not needed ? > + > + rc = stk1160_start_streaming(dev); > + > + return rc; > +} > + > +/* abort streaming and wait for last buffer */ > +static int stop_streaming(struct vb2_queue *vq) > +{ > + struct stk1160 *dev = vb2_get_drv_priv(vq); > + int rc; ? > + > + rc = stk1160_stop_streaming(dev, true); > + > + return rc; > +} -- Regards, Sylwester -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html