PageRenderTime 46ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/staging/cx25821/cx25821-videoioctl.c

https://github.com/arkas/Samsung-GT-I5510-Kernel
C | 496 lines | 392 code | 75 blank | 29 comment | 83 complexity | bbeddda21e52d26ca0529525a7f63903 MD5 | raw file
  1. /*
  2. * Driver for the Conexant CX25821 PCIe bridge
  3. *
  4. * Copyright (C) 2009 Conexant Systems Inc.
  5. * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
  6. * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. *
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. */
  23. #include "cx25821-video.h"
  24. static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
  25. {
  26. struct cx25821_buffer *buf =
  27. container_of(vb, struct cx25821_buffer, vb);
  28. struct cx25821_buffer *prev;
  29. struct cx25821_fh *fh = vq->priv_data;
  30. struct cx25821_dev *dev = fh->dev;
  31. struct cx25821_dmaqueue *q = &dev->vidq[VIDEO_IOCTL_CH];
  32. /* add jump to stopper */
  33. buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
  34. buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
  35. buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
  36. dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
  37. if (!list_empty(&q->queued)) {
  38. list_add_tail(&buf->vb.queue, &q->queued);
  39. buf->vb.state = VIDEOBUF_QUEUED;
  40. dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
  41. buf->vb.i);
  42. } else if (list_empty(&q->active)) {
  43. list_add_tail(&buf->vb.queue, &q->active);
  44. cx25821_start_video_dma(dev, q, buf,
  45. &dev->sram_channels[VIDEO_IOCTL_CH]);
  46. buf->vb.state = VIDEOBUF_ACTIVE;
  47. buf->count = q->count++;
  48. mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
  49. dprintk(2,
  50. "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
  51. buf, buf->vb.i, buf->count, q->count);
  52. } else {
  53. prev =
  54. list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
  55. if (prev->vb.width == buf->vb.width
  56. && prev->vb.height == buf->vb.height
  57. && prev->fmt == buf->fmt) {
  58. list_add_tail(&buf->vb.queue, &q->active);
  59. buf->vb.state = VIDEOBUF_ACTIVE;
  60. buf->count = q->count++;
  61. prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
  62. /* 64 bit bits 63-32 */
  63. prev->risc.jmp[2] = cpu_to_le32(0);
  64. dprintk(2,
  65. "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
  66. buf, buf->vb.i, buf->count);
  67. } else {
  68. list_add_tail(&buf->vb.queue, &q->queued);
  69. buf->vb.state = VIDEOBUF_QUEUED;
  70. dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
  71. buf->vb.i);
  72. }
  73. }
  74. if (list_empty(&q->active)) {
  75. dprintk(2, "active queue empty!\n");
  76. }
  77. }
  78. static struct videobuf_queue_ops cx25821_video_qops = {
  79. .buf_setup = buffer_setup,
  80. .buf_prepare = buffer_prepare,
  81. .buf_queue = buffer_queue,
  82. .buf_release = buffer_release,
  83. };
  84. static int video_open(struct file *file)
  85. {
  86. int minor = video_devdata(file)->minor;
  87. struct cx25821_dev *h, *dev = NULL;
  88. struct cx25821_fh *fh;
  89. struct list_head *list;
  90. enum v4l2_buf_type type = 0;
  91. u32 pix_format;
  92. lock_kernel();
  93. list_for_each(list, &cx25821_devlist) {
  94. h = list_entry(list, struct cx25821_dev, devlist);
  95. if (h->ioctl_dev && h->ioctl_dev->minor == minor) {
  96. dev = h;
  97. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  98. }
  99. }
  100. if (NULL == dev) {
  101. unlock_kernel();
  102. return -ENODEV;
  103. }
  104. printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]);
  105. /* allocate + initialize per filehandle data */
  106. fh = kzalloc(sizeof(*fh), GFP_KERNEL);
  107. if (NULL == fh) {
  108. unlock_kernel();
  109. return -ENOMEM;
  110. }
  111. file->private_data = fh;
  112. fh->dev = dev;
  113. fh->type = type;
  114. fh->width = 720;
  115. if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
  116. fh->height = 576;
  117. else
  118. fh->height = 480;
  119. dev->channel_opened = VIDEO_IOCTL_CH;
  120. pix_format = V4L2_PIX_FMT_YUYV;
  121. fh->fmt = format_by_fourcc(pix_format);
  122. v4l2_prio_open(&dev->prio, &fh->prio);
  123. videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
  124. &dev->pci->dev, &dev->slock,
  125. V4L2_BUF_TYPE_VIDEO_CAPTURE,
  126. V4L2_FIELD_INTERLACED,
  127. sizeof(struct cx25821_buffer), fh);
  128. dprintk(1, "post videobuf_queue_init()\n");
  129. unlock_kernel();
  130. return 0;
  131. }
  132. static ssize_t video_read(struct file *file, char __user * data, size_t count,
  133. loff_t * ppos)
  134. {
  135. struct cx25821_fh *fh = file->private_data;
  136. switch (fh->type) {
  137. case V4L2_BUF_TYPE_VIDEO_CAPTURE:
  138. if (res_locked(fh->dev, RESOURCE_VIDEO_IOCTL))
  139. return -EBUSY;
  140. return videobuf_read_one(&fh->vidq, data, count, ppos,
  141. file->f_flags & O_NONBLOCK);
  142. default:
  143. BUG();
  144. return 0;
  145. }
  146. }
  147. static unsigned int video_poll(struct file *file,
  148. struct poll_table_struct *wait)
  149. {
  150. struct cx25821_fh *fh = file->private_data;
  151. struct cx25821_buffer *buf;
  152. if (res_check(fh, RESOURCE_VIDEO_IOCTL)) {
  153. /* streaming capture */
  154. if (list_empty(&fh->vidq.stream))
  155. return POLLERR;
  156. buf = list_entry(fh->vidq.stream.next,
  157. struct cx25821_buffer, vb.stream);
  158. } else {
  159. /* read() capture */
  160. buf = (struct cx25821_buffer *)fh->vidq.read_buf;
  161. if (NULL == buf)
  162. return POLLERR;
  163. }
  164. poll_wait(file, &buf->vb.done, wait);
  165. if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
  166. return POLLIN | POLLRDNORM;
  167. return 0;
  168. }
  169. static int video_release(struct file *file)
  170. {
  171. struct cx25821_fh *fh = file->private_data;
  172. struct cx25821_dev *dev = fh->dev;
  173. /* stop video capture */
  174. if (res_check(fh, RESOURCE_VIDEO_IOCTL)) {
  175. videobuf_queue_cancel(&fh->vidq);
  176. res_free(dev, fh, RESOURCE_VIDEO_IOCTL);
  177. }
  178. if (fh->vidq.read_buf) {
  179. buffer_release(&fh->vidq, fh->vidq.read_buf);
  180. kfree(fh->vidq.read_buf);
  181. }
  182. videobuf_mmap_free(&fh->vidq);
  183. v4l2_prio_close(&dev->prio, &fh->prio);
  184. file->private_data = NULL;
  185. kfree(fh);
  186. return 0;
  187. }
  188. static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
  189. {
  190. struct cx25821_fh *fh = priv;
  191. struct cx25821_dev *dev = fh->dev;
  192. if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
  193. return -EINVAL;
  194. }
  195. if (unlikely(i != fh->type)) {
  196. return -EINVAL;
  197. }
  198. if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO_IOCTL)))) {
  199. return -EBUSY;
  200. }
  201. return videobuf_streamon(get_queue(fh));
  202. }
  203. static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
  204. {
  205. struct cx25821_fh *fh = priv;
  206. struct cx25821_dev *dev = fh->dev;
  207. int err, res;
  208. if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
  209. return -EINVAL;
  210. if (i != fh->type)
  211. return -EINVAL;
  212. res = get_resource(fh, RESOURCE_VIDEO_IOCTL);
  213. err = videobuf_streamoff(get_queue(fh));
  214. if (err < 0)
  215. return err;
  216. res_free(dev, fh, res);
  217. return 0;
  218. }
  219. static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
  220. struct v4l2_format *f)
  221. {
  222. struct cx25821_fh *fh = priv;
  223. struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
  224. int err;
  225. if (fh) {
  226. err = v4l2_prio_check(&dev->prio, &fh->prio);
  227. if (0 != err)
  228. return err;
  229. }
  230. dprintk(2, "%s()\n", __func__);
  231. err = vidioc_try_fmt_vid_cap(file, priv, f);
  232. if (0 != err)
  233. return err;
  234. fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
  235. fh->width = f->fmt.pix.width;
  236. fh->height = f->fmt.pix.height;
  237. fh->vidq.field = f->fmt.pix.field;
  238. dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
  239. fh->height, fh->vidq.field);
  240. cx25821_call_all(dev, video, s_fmt, f);
  241. return 0;
  242. }
  243. static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
  244. {
  245. struct cx25821_fh *fh = priv;
  246. return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
  247. }
  248. static long video_ioctl_set(struct file *file, unsigned int cmd,
  249. unsigned long arg)
  250. {
  251. struct cx25821_fh *fh = file->private_data;
  252. struct cx25821_dev *dev = fh->dev;
  253. struct downstream_user_struct *data_from_user;
  254. int command;
  255. int width = 720;
  256. int selected_channel = 0, pix_format = 0, i = 0;
  257. int cif_enable = 0, cif_width = 0;
  258. u32 value = 0;
  259. data_from_user = (struct downstream_user_struct *)arg;
  260. if (!data_from_user) {
  261. printk("cx25821 in %s(): User data is INVALID. Returning.\n",
  262. __func__);
  263. return 0;
  264. }
  265. command = data_from_user->command;
  266. if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
  267. && command != ENABLE_CIF_RESOLUTION && command != REG_READ
  268. && command != REG_WRITE && command != MEDUSA_READ
  269. && command != MEDUSA_WRITE) {
  270. return 0;
  271. }
  272. switch (command) {
  273. case SET_VIDEO_STD:
  274. dev->tvnorm =
  275. !strcmp(data_from_user->vid_stdname,
  276. "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
  277. medusa_set_videostandard(dev);
  278. break;
  279. case SET_PIXEL_FORMAT:
  280. selected_channel = data_from_user->decoder_select;
  281. pix_format = data_from_user->pixel_format;
  282. if (!(selected_channel <= 7 && selected_channel >= 0)) {
  283. selected_channel -= 4;
  284. selected_channel = selected_channel % 8;
  285. }
  286. if (selected_channel >= 0)
  287. cx25821_set_pixel_format(dev, selected_channel,
  288. pix_format);
  289. break;
  290. case ENABLE_CIF_RESOLUTION:
  291. selected_channel = data_from_user->decoder_select;
  292. cif_enable = data_from_user->cif_resolution_enable;
  293. cif_width = data_from_user->cif_width;
  294. if (cif_enable) {
  295. if (dev->tvnorm & V4L2_STD_PAL_BG
  296. || dev->tvnorm & V4L2_STD_PAL_DK)
  297. width = 352;
  298. else
  299. width = (cif_width == 320
  300. || cif_width == 352) ? cif_width : 320;
  301. }
  302. if (!(selected_channel <= 7 && selected_channel >= 0)) {
  303. selected_channel -= 4;
  304. selected_channel = selected_channel % 8;
  305. }
  306. if (selected_channel <= 7 && selected_channel >= 0) {
  307. dev->use_cif_resolution[selected_channel] = cif_enable;
  308. dev->cif_width[selected_channel] = width;
  309. } else {
  310. for (i = 0; i < VID_CHANNEL_NUM; i++) {
  311. dev->use_cif_resolution[i] = cif_enable;
  312. dev->cif_width[i] = width;
  313. }
  314. }
  315. medusa_set_resolution(dev, width, selected_channel);
  316. break;
  317. case REG_READ:
  318. data_from_user->reg_data = cx_read(data_from_user->reg_address);
  319. break;
  320. case REG_WRITE:
  321. cx_write(data_from_user->reg_address, data_from_user->reg_data);
  322. break;
  323. case MEDUSA_READ:
  324. value =
  325. cx25821_i2c_read(&dev->i2c_bus[0],
  326. (u16) data_from_user->reg_address,
  327. &data_from_user->reg_data);
  328. break;
  329. case MEDUSA_WRITE:
  330. cx25821_i2c_write(&dev->i2c_bus[0],
  331. (u16) data_from_user->reg_address,
  332. data_from_user->reg_data);
  333. break;
  334. }
  335. return 0;
  336. }
  337. static int vidioc_log_status(struct file *file, void *priv)
  338. {
  339. struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
  340. char name[32 + 2];
  341. snprintf(name, sizeof(name), "%s/2", dev->name);
  342. printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
  343. dev->name);
  344. cx25821_call_all(dev, core, log_status);
  345. printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
  346. dev->name);
  347. return 0;
  348. }
  349. static int vidioc_s_ctrl(struct file *file, void *priv,
  350. struct v4l2_control *ctl)
  351. {
  352. struct cx25821_fh *fh = priv;
  353. struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
  354. int err;
  355. if (fh) {
  356. err = v4l2_prio_check(&dev->prio, &fh->prio);
  357. if (0 != err)
  358. return err;
  359. }
  360. return 0;
  361. }
  362. // exported stuff
  363. static const struct v4l2_file_operations video_fops = {
  364. .owner = THIS_MODULE,
  365. .open = video_open,
  366. .release = video_release,
  367. .read = video_read,
  368. .poll = video_poll,
  369. .mmap = video_mmap,
  370. .ioctl = video_ioctl_set,
  371. };
  372. static const struct v4l2_ioctl_ops video_ioctl_ops = {
  373. .vidioc_querycap = vidioc_querycap,
  374. .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
  375. .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
  376. .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
  377. .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
  378. .vidioc_reqbufs = vidioc_reqbufs,
  379. .vidioc_querybuf = vidioc_querybuf,
  380. .vidioc_qbuf = vidioc_qbuf,
  381. .vidioc_dqbuf = vidioc_dqbuf,
  382. #ifdef TUNER_FLAG
  383. .vidioc_s_std = vidioc_s_std,
  384. .vidioc_querystd = vidioc_querystd,
  385. #endif
  386. .vidioc_cropcap = vidioc_cropcap,
  387. .vidioc_s_crop = vidioc_s_crop,
  388. .vidioc_g_crop = vidioc_g_crop,
  389. .vidioc_enum_input = vidioc_enum_input,
  390. .vidioc_g_input = vidioc_g_input,
  391. .vidioc_s_input = vidioc_s_input,
  392. .vidioc_g_ctrl = vidioc_g_ctrl,
  393. .vidioc_s_ctrl = vidioc_s_ctrl,
  394. .vidioc_queryctrl = vidioc_queryctrl,
  395. .vidioc_streamon = vidioc_streamon,
  396. .vidioc_streamoff = vidioc_streamoff,
  397. .vidioc_log_status = vidioc_log_status,
  398. .vidioc_g_priority = vidioc_g_priority,
  399. .vidioc_s_priority = vidioc_s_priority,
  400. #ifdef CONFIG_VIDEO_V4L1_COMPAT
  401. .vidiocgmbuf = vidiocgmbuf,
  402. #endif
  403. #ifdef TUNER_FLAG
  404. .vidioc_g_tuner = vidioc_g_tuner,
  405. .vidioc_s_tuner = vidioc_s_tuner,
  406. .vidioc_g_frequency = vidioc_g_frequency,
  407. .vidioc_s_frequency = vidioc_s_frequency,
  408. #endif
  409. #ifdef CONFIG_VIDEO_ADV_DEBUG
  410. .vidioc_g_register = vidioc_g_register,
  411. .vidioc_s_register = vidioc_s_register,
  412. #endif
  413. };
  414. struct video_device cx25821_videoioctl_template = {
  415. .name = "cx25821-videoioctl",
  416. .fops = &video_fops,
  417. .minor = -1,
  418. .ioctl_ops = &video_ioctl_ops,
  419. .tvnorms = CX25821_NORMS,
  420. .current_norm = V4L2_STD_NTSC_M,
  421. };