Commit f4e5e14f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media fixes from Mauro Carvalho Chehab:
 - Compilation fixes for GCC < 4.4.6
 - one Kbuild dependency select fix (selecting videobuf on msi3101)
 - driver fixes on tda10071, e4000, msi3101, soc_camera, s5p-jpeg,
   saa7134 and adv7511
 - some device quirks needed to make them work properly
 - some videobuf2 core regression fixes for some features used only on
   embedded drivers

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media:
  [media] saa7134: Fix crash when device is closed before streamoff
  [media] adv7511: fix error return code in adv7511_probe()
  [media] ths8200: fix compilation with GCC < 4.4.6
  [media] ad9389b: fix compilation with GCC < 4.4.6
  [media] adv7511: fix compilation with GCC < 4.4.6
  [media] adv7842: fix compilation with GCC < 4.4.6
  [media] s5p-jpeg: Initialize vfd_decoder->vfl_dir field
  [media] videobuf2-dc: Fix support for mappings without struct page in userptr mode
  [media] vb2: Allow queuing OUTPUT buffers with zeroed 'bytesused'
  [media] mx3-camera: locking cleanup in mx3_videobuf_queue()
  [media] sh_vou: almost forever loop in sh_vou_try_fmt_vid_out()
  [media] tda10071: change firmware download condition
  [media] msi3101: correct max videobuf2 alloc
  [media] Add HCL T12Rg-H to STK webcam upside-down table
  [media] msi3101: Kconfig select VIDEOBUF2_VMALLOC
  [media] msi3101: msi3101_ioctl_ops can be static
  [media] e4000: fix PLL calc bug on 32-bit arch
  [media] uvcvideo: quirk PROBE_DEF for Microsoft Lifecam NX-3000
  [media] uvcvideo: quirk PROBE_DEF for Dell SP2008WFP monitor
parents 0d645a8b 9c9cff55
...@@ -912,14 +912,8 @@ static int tda10071_init(struct dvb_frontend *fe) ...@@ -912,14 +912,8 @@ static int tda10071_init(struct dvb_frontend *fe)
{ 0xd5, 0x03, 0x03 }, { 0xd5, 0x03, 0x03 },
}; };
/* firmware status */ if (priv->warm) {
ret = tda10071_rd_reg(priv, 0x51, &tmp);
if (ret)
goto error;
if (!tmp) {
/* warm state - wake up device from sleep */ /* warm state - wake up device from sleep */
priv->warm = 1;
for (i = 0; i < ARRAY_SIZE(tab); i++) { for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = tda10071_wr_reg_mask(priv, tab[i].reg, ret = tda10071_wr_reg_mask(priv, tab[i].reg,
...@@ -937,7 +931,6 @@ static int tda10071_init(struct dvb_frontend *fe) ...@@ -937,7 +931,6 @@ static int tda10071_init(struct dvb_frontend *fe)
goto error; goto error;
} else { } else {
/* cold state - try to download firmware */ /* cold state - try to download firmware */
priv->warm = 0;
/* request the firmware, this will block and timeout */ /* request the firmware, this will block and timeout */
ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent); ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
......
...@@ -628,16 +628,13 @@ static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -628,16 +628,13 @@ static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
static const struct v4l2_dv_timings_cap ad9389b_timings_cap = { static const struct v4l2_dv_timings_cap ad9389b_timings_cap = {
.type = V4L2_DV_BT_656_1120, .type = V4L2_DV_BT_656_1120,
.bt = { /* keep this initialization for compatibility with GCC < 4.4.6 */
.max_width = 1920, .reserved = { 0 },
.max_height = 1200, V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
.min_pixelclock = 25000000, V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
.max_pixelclock = 170000000,
.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM, V4L2_DV_BT_CAP_CUSTOM)
},
}; };
static int ad9389b_s_dv_timings(struct v4l2_subdev *sd, static int ad9389b_s_dv_timings(struct v4l2_subdev *sd,
......
...@@ -119,16 +119,14 @@ static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq); ...@@ -119,16 +119,14 @@ static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
static const struct v4l2_dv_timings_cap adv7511_timings_cap = { static const struct v4l2_dv_timings_cap adv7511_timings_cap = {
.type = V4L2_DV_BT_656_1120, .type = V4L2_DV_BT_656_1120,
.bt = { /* keep this initialization for compatibility with GCC < 4.4.6 */
.max_width = ADV7511_MAX_WIDTH, .reserved = { 0 },
.max_height = ADV7511_MAX_HEIGHT, V4L2_INIT_BT_TIMINGS(0, ADV7511_MAX_WIDTH, 0, ADV7511_MAX_HEIGHT,
.min_pixelclock = ADV7511_MIN_PIXELCLOCK, ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK,
.max_pixelclock = ADV7511_MAX_PIXELCLOCK, V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM, V4L2_DV_BT_CAP_CUSTOM)
},
}; };
static inline struct adv7511_state *get_adv7511_state(struct v4l2_subdev *sd) static inline struct adv7511_state *get_adv7511_state(struct v4l2_subdev *sd)
...@@ -1126,6 +1124,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * ...@@ -1126,6 +1124,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
state->i2c_edid = i2c_new_dummy(client->adapter, state->i2c_edid_addr >> 1); state->i2c_edid = i2c_new_dummy(client->adapter, state->i2c_edid_addr >> 1);
if (state->i2c_edid == NULL) { if (state->i2c_edid == NULL) {
v4l2_err(sd, "failed to register edid i2c client\n"); v4l2_err(sd, "failed to register edid i2c client\n");
err = -ENOMEM;
goto err_entity; goto err_entity;
} }
...@@ -1133,6 +1132,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * ...@@ -1133,6 +1132,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
state->work_queue = create_singlethread_workqueue(sd->name); state->work_queue = create_singlethread_workqueue(sd->name);
if (state->work_queue == NULL) { if (state->work_queue == NULL) {
v4l2_err(sd, "could not create workqueue\n"); v4l2_err(sd, "could not create workqueue\n");
err = -ENOMEM;
goto err_unreg_cec; goto err_unreg_cec;
} }
......
...@@ -546,30 +546,24 @@ static inline bool is_digital_input(struct v4l2_subdev *sd) ...@@ -546,30 +546,24 @@ static inline bool is_digital_input(struct v4l2_subdev *sd)
static const struct v4l2_dv_timings_cap adv7842_timings_cap_analog = { static const struct v4l2_dv_timings_cap adv7842_timings_cap_analog = {
.type = V4L2_DV_BT_656_1120, .type = V4L2_DV_BT_656_1120,
.bt = { /* keep this initialization for compatibility with GCC < 4.4.6 */
.max_width = 1920, .reserved = { 0 },
.max_height = 1200, V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
.min_pixelclock = 25000000, V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
.max_pixelclock = 170000000,
.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM, V4L2_DV_BT_CAP_CUSTOM)
},
}; };
static const struct v4l2_dv_timings_cap adv7842_timings_cap_digital = { static const struct v4l2_dv_timings_cap adv7842_timings_cap_digital = {
.type = V4L2_DV_BT_656_1120, .type = V4L2_DV_BT_656_1120,
.bt = { /* keep this initialization for compatibility with GCC < 4.4.6 */
.max_width = 1920, .reserved = { 0 },
.max_height = 1200, V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
.min_pixelclock = 25000000, V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
.max_pixelclock = 225000000,
.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM, V4L2_DV_BT_CAP_CUSTOM)
},
}; };
static inline const struct v4l2_dv_timings_cap * static inline const struct v4l2_dv_timings_cap *
......
...@@ -46,14 +46,10 @@ struct ths8200_state { ...@@ -46,14 +46,10 @@ struct ths8200_state {
static const struct v4l2_dv_timings_cap ths8200_timings_cap = { static const struct v4l2_dv_timings_cap ths8200_timings_cap = {
.type = V4L2_DV_BT_656_1120, .type = V4L2_DV_BT_656_1120,
.bt = { /* keep this initialization for compatibility with GCC < 4.4.6 */
.max_width = 1920, .reserved = { 0 },
.max_height = 1080, V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1080, 25000000, 148500000,
.min_pixelclock = 25000000, V4L2_DV_BT_STD_CEA861, V4L2_DV_BT_CAP_PROGRESSIVE)
.max_pixelclock = 148500000,
.standards = V4L2_DV_BT_STD_CEA861,
.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE,
},
}; };
static inline struct ths8200_state *to_state(struct v4l2_subdev *sd) static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
......
...@@ -1455,6 +1455,7 @@ static int video_release(struct file *file) ...@@ -1455,6 +1455,7 @@ static int video_release(struct file *file)
/* stop video capture */ /* stop video capture */
if (res_check(fh, RESOURCE_VIDEO)) { if (res_check(fh, RESOURCE_VIDEO)) {
pm_qos_remove_request(&dev->qos_request);
videobuf_streamoff(&fh->cap); videobuf_streamoff(&fh->cap);
res_free(dev,fh,RESOURCE_VIDEO); res_free(dev,fh,RESOURCE_VIDEO);
} }
......
...@@ -1423,6 +1423,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) ...@@ -1423,6 +1423,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
jpeg->vfd_decoder->release = video_device_release; jpeg->vfd_decoder->release = video_device_release;
jpeg->vfd_decoder->lock = &jpeg->lock; jpeg->vfd_decoder->lock = &jpeg->lock;
jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev; jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1); ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
if (ret) { if (ret) {
......
...@@ -776,7 +776,7 @@ static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, ...@@ -776,7 +776,7 @@ static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1, v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
&pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0); &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
for (i = 0; ARRAY_SIZE(vou_fmt); i++) for (i = 0; i < ARRAY_SIZE(vou_fmt); i++)
if (vou_fmt[i].pfmt == pix->pixelformat) if (vou_fmt[i].pfmt == pix->pixelformat)
return 0; return 0;
......
...@@ -266,7 +266,6 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) ...@@ -266,7 +266,6 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
struct idmac_video_param *video = &ichan->params.video; struct idmac_video_param *video = &ichan->params.video;
const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt; const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
unsigned long flags;
dma_cookie_t cookie; dma_cookie_t cookie;
size_t new_size; size_t new_size;
...@@ -328,7 +327,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) ...@@ -328,7 +327,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
#endif #endif
spin_lock_irqsave(&mx3_cam->lock, flags); spin_lock_irq(&mx3_cam->lock);
list_add_tail(&buf->queue, &mx3_cam->capture); list_add_tail(&buf->queue, &mx3_cam->capture);
if (!mx3_cam->active) if (!mx3_cam->active)
...@@ -351,7 +350,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) ...@@ -351,7 +350,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
if (mx3_cam->active == buf) if (mx3_cam->active == buf)
mx3_cam->active = NULL; mx3_cam->active = NULL;
spin_unlock_irqrestore(&mx3_cam->lock, flags); spin_unlock_irq(&mx3_cam->lock);
error: error:
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
*/ */
#include "e4000_priv.h" #include "e4000_priv.h"
#include <linux/math64.h>
/* write multiple registers */ /* write multiple registers */
static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
...@@ -233,7 +234,7 @@ static int e4000_set_params(struct dvb_frontend *fe) ...@@ -233,7 +234,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
* or more. * or more.
*/ */
f_vco = c->frequency * e4000_pll_lut[i].mul; f_vco = c->frequency * e4000_pll_lut[i].mul;
sigma_delta = 0x10000UL * (f_vco % priv->cfg->clock) / priv->cfg->clock; sigma_delta = div_u64(0x10000ULL * (f_vco % priv->cfg->clock), priv->cfg->clock);
buf[0] = f_vco / priv->cfg->clock; buf[0] = f_vco / priv->cfg->clock;
buf[1] = (sigma_delta >> 0) & 0xff; buf[1] = (sigma_delta >> 0) & 0xff;
buf[2] = (sigma_delta >> 8) & 0xff; buf[2] = (sigma_delta >> 8) & 0xff;
......
...@@ -111,6 +111,13 @@ static const struct dmi_system_id stk_upside_down_dmi_table[] = { ...@@ -111,6 +111,13 @@ static const struct dmi_system_id stk_upside_down_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "F3JC") DMI_MATCH(DMI_PRODUCT_NAME, "F3JC")
} }
}, },
{
.ident = "T12Rg-H",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HCL Infosystems Limited"),
DMI_MATCH(DMI_PRODUCT_NAME, "T12Rg-H")
}
},
{} {}
}; };
......
...@@ -2090,6 +2090,15 @@ static struct usb_device_id uvc_ids[] = { ...@@ -2090,6 +2090,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1, .bInterfaceSubClass = 1,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX }, .driver_info = UVC_QUIRK_PROBE_MINMAX },
/* Microsoft Lifecam NX-3000 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x045e,
.idProduct = 0x0721,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_DEF },
/* Microsoft Lifecam VX-7000 */ /* Microsoft Lifecam VX-7000 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO, | USB_DEVICE_ID_MATCH_INT_INFO,
...@@ -2174,6 +2183,15 @@ static struct usb_device_id uvc_ids[] = { ...@@ -2174,6 +2183,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1, .bInterfaceSubClass = 1,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_DEF }, .driver_info = UVC_QUIRK_PROBE_DEF },
/* Dell SP2008WFP Monitor */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x05a9,
.idProduct = 0x2641,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_DEF },
/* Dell Alienware X51 */ /* Dell Alienware X51 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO, | USB_DEVICE_ID_MATCH_INT_INFO,
......
...@@ -353,7 +353,9 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) ...@@ -353,7 +353,9 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
if (b->m.planes[plane].bytesused > length) if (b->m.planes[plane].bytesused > length)
return -EINVAL; return -EINVAL;
if (b->m.planes[plane].data_offset >=
if (b->m.planes[plane].data_offset > 0 &&
b->m.planes[plane].data_offset >=
b->m.planes[plane].bytesused) b->m.planes[plane].bytesused)
return -EINVAL; return -EINVAL;
} }
......
...@@ -423,6 +423,39 @@ static inline int vma_is_io(struct vm_area_struct *vma) ...@@ -423,6 +423,39 @@ static inline int vma_is_io(struct vm_area_struct *vma)
return !!(vma->vm_flags & (VM_IO | VM_PFNMAP)); return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
} }
static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
struct vm_area_struct *vma, unsigned long *res)
{
unsigned long pfn, start_pfn, prev_pfn;
unsigned int i;
int ret;
if (!vma_is_io(vma))
return -EFAULT;
ret = follow_pfn(vma, start, &pfn);
if (ret)
return ret;
start_pfn = pfn;
start += PAGE_SIZE;
for (i = 1; i < n_pages; ++i, start += PAGE_SIZE) {
prev_pfn = pfn;
ret = follow_pfn(vma, start, &pfn);
if (ret) {
pr_err("no page for address %lu\n", start);
return ret;
}
if (pfn != prev_pfn + 1)
return -EINVAL;
}
*res = start_pfn;
return 0;
}
static int vb2_dc_get_user_pages(unsigned long start, struct page **pages, static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
int n_pages, struct vm_area_struct *vma, int write) int n_pages, struct vm_area_struct *vma, int write)
{ {
...@@ -433,6 +466,9 @@ static int vb2_dc_get_user_pages(unsigned long start, struct page **pages, ...@@ -433,6 +466,9 @@ static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
unsigned long pfn; unsigned long pfn;
int ret = follow_pfn(vma, start, &pfn); int ret = follow_pfn(vma, start, &pfn);
if (!pfn_valid(pfn))
return -EINVAL;
if (ret) { if (ret) {
pr_err("no page for address %lu\n", start); pr_err("no page for address %lu\n", start);
return ret; return ret;
...@@ -468,16 +504,49 @@ static void vb2_dc_put_userptr(void *buf_priv) ...@@ -468,16 +504,49 @@ static void vb2_dc_put_userptr(void *buf_priv)
struct vb2_dc_buf *buf = buf_priv; struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt; struct sg_table *sgt = buf->dma_sgt;
if (sgt) {
dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
if (!vma_is_io(buf->vma)) if (!vma_is_io(buf->vma))
vb2_dc_sgt_foreach_page(sgt, vb2_dc_put_dirty_page); vb2_dc_sgt_foreach_page(sgt, vb2_dc_put_dirty_page);
sg_free_table(sgt); sg_free_table(sgt);
kfree(sgt); kfree(sgt);
}
vb2_put_vma(buf->vma); vb2_put_vma(buf->vma);
kfree(buf); kfree(buf);
} }
/*
* For some kind of reserved memory there might be no struct page available,
* so all that can be done to support such 'pages' is to try to convert
* pfn to dma address or at the last resort just assume that
* dma address == physical address (like it has been assumed in earlier version
* of videobuf2-dma-contig
*/
#ifdef __arch_pfn_to_dma
static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn)
{
return (dma_addr_t)__arch_pfn_to_dma(dev, pfn);
}
#elif defined(__pfn_to_bus)
static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn)
{
return (dma_addr_t)__pfn_to_bus(pfn);
}
#elif defined(__pfn_to_phys)
static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn)
{
return (dma_addr_t)__pfn_to_phys(pfn);
}
#else
static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn)
{
/* really, we cannot do anything better at this point */
return (dma_addr_t)(pfn) << PAGE_SHIFT;
}
#endif
static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write) unsigned long size, int write)
{ {
...@@ -548,6 +617,14 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, ...@@ -548,6 +617,14 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
/* extract page list from userspace mapping */ /* extract page list from userspace mapping */
ret = vb2_dc_get_user_pages(start, pages, n_pages, vma, write); ret = vb2_dc_get_user_pages(start, pages, n_pages, vma, write);
if (ret) { if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, &pfn) == 0) {
buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, pfn);
buf->size = size;
kfree(pages);
return buf;
}
pr_err("failed to get user pages\n"); pr_err("failed to get user pages\n");
goto fail_vma; goto fail_vma;
} }
......
config USB_MSI3101 config USB_MSI3101
tristate "Mirics MSi3101 SDR Dongle" tristate "Mirics MSi3101 SDR Dongle"
depends on USB && VIDEO_DEV && VIDEO_V4L2 depends on USB && VIDEO_DEV && VIDEO_V4L2
select VIDEOBUF2_VMALLOC
...@@ -1131,7 +1131,13 @@ static int msi3101_queue_setup(struct vb2_queue *vq, ...@@ -1131,7 +1131,13 @@ static int msi3101_queue_setup(struct vb2_queue *vq,
/* Absolute min and max number of buffers available for mmap() */ /* Absolute min and max number of buffers available for mmap() */
*nbuffers = 32; *nbuffers = 32;
*nplanes = 1; *nplanes = 1;
sizes[0] = PAGE_ALIGN(3 * 3072); /* 3 * 768 * 4 */ /*
* 3, wMaxPacketSize 3x 1024 bytes
* 504, max IQ sample pairs per 1024 frame
* 2, two samples, I and Q
* 4, 32-bit float
*/
sizes[0] = PAGE_ALIGN(3 * 504 * 2 * 4); /* = 12096 */
dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
__func__, *nbuffers, sizes[0]); __func__, *nbuffers, sizes[0]);
return 0; return 0;
...@@ -1657,7 +1663,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, ...@@ -1657,7 +1663,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
f->frequency * 625UL / 10UL); f->frequency * 625UL / 10UL);
} }
const struct v4l2_ioctl_ops msi3101_ioctl_ops = { static const struct v4l2_ioctl_ops msi3101_ioctl_ops = {
.vidioc_querycap = msi3101_querycap, .vidioc_querycap = msi3101_querycap,
.vidioc_enum_input = msi3101_enum_input, .vidioc_enum_input = msi3101_enum_input,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment