saa7134-empress.c 11.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 *
 * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>

#include "saa7134-reg.h"
#include "saa7134.h"

#include <media/saa6752hs.h>
30
#include <media/v4l2-common.h>
L
Linus Torvalds 已提交
31 32 33 34 35 36 37

/* ------------------------------------------------------------------ */

MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");

static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
38

L
Linus Torvalds 已提交
39 40 41
module_param_array(empress_nr, int, NULL, 0444);
MODULE_PARM_DESC(empress_nr,"ts device number");

42
static unsigned int debug;
L
Linus Torvalds 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages");

#define dprintk(fmt, arg...)	if (debug)			\
	printk(KERN_DEBUG "%s/empress: " fmt, dev->name , ## arg)

/* ------------------------------------------------------------------ */

static void ts_reset_encoder(struct saa7134_dev* dev)
{
	if (!dev->empress_started)
		return;

	saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
	msleep(10);
58
	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
L
Linus Torvalds 已提交
59 60 61 62 63 64
	msleep(100);
	dev->empress_started = 0;
}

static int ts_init_encoder(struct saa7134_dev* dev)
{
65
	u32 leading_null_bytes = 0;
66

67 68 69 70 71 72 73 74 75
	/* If more cards start to need this, then this
	   should probably be added to the card definitions. */
	switch (dev->board) {
	case SAA7134_BOARD_BEHOLD_M6:
	case SAA7134_BOARD_BEHOLD_M63:
	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
		leading_null_bytes = 1;
		break;
	}
L
Linus Torvalds 已提交
76
	ts_reset_encoder(dev);
77
	saa_call_all(dev, core, init, leading_null_bytes);
L
Linus Torvalds 已提交
78
	dev->empress_started = 1;
79
	return 0;
L
Linus Torvalds 已提交
80 81 82 83
}

/* ------------------------------------------------------------------ */

84
static int ts_open(struct file *file)
L
Linus Torvalds 已提交
85
{
86
	struct video_device *vdev = video_devdata(file);
87
	struct saa7134_dev *dev = video_drvdata(file);
L
Linus Torvalds 已提交
88 89
	int err;

90
	dprintk("open dev=%s\n", video_device_node_name(vdev));
L
Linus Torvalds 已提交
91
	err = -EBUSY;
92
	if (!mutex_trylock(&dev->empress_tsq.vb_lock))
93
		return err;
94
	if (atomic_read(&dev->empress_users))
95
		goto done;
L
Linus Torvalds 已提交
96

97 98 99 100
	/* Unmute audio */
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
		saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));

101
	atomic_inc(&dev->empress_users);
L
Linus Torvalds 已提交
102 103 104 105
	file->private_data = dev;
	err = 0;

done:
106
	mutex_unlock(&dev->empress_tsq.vb_lock);
L
Linus Torvalds 已提交
107 108 109
	return err;
}

110
static int ts_release(struct file *file)
L
Linus Torvalds 已提交
111 112 113
{
	struct saa7134_dev *dev = file->private_data;

114
	videobuf_stop(&dev->empress_tsq);
L
Linus Torvalds 已提交
115 116 117 118 119
	videobuf_mmap_free(&dev->empress_tsq);

	/* stop the encoder */
	ts_reset_encoder(dev);

120 121 122 123
	/* Mute audio */
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
		saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));

124
	atomic_dec(&dev->empress_users);
125

L
Linus Torvalds 已提交
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
	return 0;
}

static ssize_t
ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
	struct saa7134_dev *dev = file->private_data;

	if (!dev->empress_started)
		ts_init_encoder(dev);

	return videobuf_read_stream(&dev->empress_tsq,
				    data, count, ppos, 0,
				    file->f_flags & O_NONBLOCK);
}

static unsigned int
ts_poll(struct file *file, struct poll_table_struct *wait)
{
	struct saa7134_dev *dev = file->private_data;

	return videobuf_poll_stream(file, &dev->empress_tsq, wait);
}


static int
ts_mmap(struct file *file, struct vm_area_struct * vma)
{
	struct saa7134_dev *dev = file->private_data;

	return videobuf_mmap_mapper(&dev->empress_tsq, vma);
}

159
static int empress_enum_fmt_vid_cap(struct file *file, void  *priv,
160 161 162 163
					struct v4l2_fmtdesc *f)
{
	if (f->index != 0)
		return -EINVAL;
L
Linus Torvalds 已提交
164

165 166
	strlcpy(f->description, "MPEG TS", sizeof(f->description));
	f->pixelformat = V4L2_PIX_FMT_MPEG;
167
	f->flags = V4L2_FMT_FLAG_COMPRESSED;
168 169
	return 0;
}
L
Linus Torvalds 已提交
170

171
static int empress_g_fmt_vid_cap(struct file *file, void *priv,
172 173
				struct v4l2_format *f)
{
174
	struct saa7134_dev *dev = file->private_data;
175
	struct v4l2_mbus_framefmt mbus_fmt;
L
Linus Torvalds 已提交
176

177
	saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt);
L
Linus Torvalds 已提交
178

179
	v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
180 181
	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
182 183
	f->fmt.pix.bytesperline = 0;
	f->fmt.pix.priv = 0;
L
Linus Torvalds 已提交
184

185 186
	return 0;
}
L
Linus Torvalds 已提交
187

188
static int empress_s_fmt_vid_cap(struct file *file, void *priv,
189 190
				struct v4l2_format *f)
{
191
	struct saa7134_dev *dev = file->private_data;
192
	struct v4l2_mbus_framefmt mbus_fmt;
L
Linus Torvalds 已提交
193

194 195 196
	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
	saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
	v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
L
Linus Torvalds 已提交
197

198 199
	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
200 201
	f->fmt.pix.bytesperline = 0;
	f->fmt.pix.priv = 0;
L
Linus Torvalds 已提交
202

203 204 205
	return 0;
}

206 207 208 209
static int empress_try_fmt_vid_cap(struct file *file, void *priv,
				struct v4l2_format *f)
{
	struct saa7134_dev *dev = file->private_data;
210 211 212 213 214
	struct v4l2_mbus_framefmt mbus_fmt;

	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
	saa_call_all(dev, video, try_mbus_fmt, &mbus_fmt);
	v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
215 216 217

	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
218 219
	f->fmt.pix.bytesperline = 0;
	f->fmt.pix.priv = 0;
220 221 222

	return 0;
}
223 224 225 226

static int empress_reqbufs(struct file *file, void *priv,
					struct v4l2_requestbuffers *p)
{
227
	struct saa7134_dev *dev = file->private_data;
228 229 230 231 232 233 234

	return videobuf_reqbufs(&dev->empress_tsq, p);
}

static int empress_querybuf(struct file *file, void *priv,
					struct v4l2_buffer *b)
{
235
	struct saa7134_dev *dev = file->private_data;
236 237 238 239 240 241

	return videobuf_querybuf(&dev->empress_tsq, b);
}

static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
242
	struct saa7134_dev *dev = file->private_data;
243 244 245 246 247 248

	return videobuf_qbuf(&dev->empress_tsq, b);
}

static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
249
	struct saa7134_dev *dev = file->private_data;
250 251 252 253 254 255 256 257

	return videobuf_dqbuf(&dev->empress_tsq, b,
				file->f_flags & O_NONBLOCK);
}

static int empress_streamon(struct file *file, void *priv,
					enum v4l2_buf_type type)
{
258
	struct saa7134_dev *dev = file->private_data;
259 260 261 262 263 264 265

	return videobuf_streamon(&dev->empress_tsq);
}

static int empress_streamoff(struct file *file, void *priv,
					enum v4l2_buf_type type)
{
266
	struct saa7134_dev *dev = file->private_data;
267 268 269 270

	return videobuf_streamoff(&dev->empress_tsq);
}

271
static const struct v4l2_file_operations ts_fops =
L
Linus Torvalds 已提交
272 273 274 275 276 277 278
{
	.owner	  = THIS_MODULE,
	.open	  = ts_open,
	.release  = ts_release,
	.read	  = ts_read,
	.poll	  = ts_poll,
	.mmap	  = ts_mmap,
279
	.ioctl	  = video_ioctl2,
L
Linus Torvalds 已提交
280 281
};

282
static const struct v4l2_ioctl_ops ts_ioctl_ops = {
283
	.vidioc_querycap		= saa7134_querycap,
284
	.vidioc_enum_fmt_vid_cap	= empress_enum_fmt_vid_cap,
285
	.vidioc_try_fmt_vid_cap		= empress_try_fmt_vid_cap,
286 287
	.vidioc_s_fmt_vid_cap		= empress_s_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap		= empress_g_fmt_vid_cap,
288 289 290 291 292 293
	.vidioc_reqbufs			= empress_reqbufs,
	.vidioc_querybuf		= empress_querybuf,
	.vidioc_qbuf			= empress_qbuf,
	.vidioc_dqbuf			= empress_dqbuf,
	.vidioc_streamon		= empress_streamon,
	.vidioc_streamoff		= empress_streamoff,
294 295 296 297 298 299 300 301 302
	.vidioc_g_frequency		= saa7134_g_frequency,
	.vidioc_s_frequency		= saa7134_s_frequency,
	.vidioc_g_tuner			= saa7134_g_tuner,
	.vidioc_s_tuner			= saa7134_s_tuner,
	.vidioc_enum_input		= saa7134_enum_input,
	.vidioc_g_input			= saa7134_g_input,
	.vidioc_s_input			= saa7134_s_input,
	.vidioc_s_std			= saa7134_s_std,
	.vidioc_g_std			= saa7134_g_std,
303 304 305 306 307 308 309 310
};

/* ----------------------------------------------------------- */

static struct video_device saa7134_empress_template = {
	.name          = "saa7134-empress",
	.fops          = &ts_fops,
	.ioctl_ops     = &ts_ioctl_ops,
311 312

	.tvnorms			= SAA7134_NORMS,
L
Linus Torvalds 已提交
313 314
};

D
David Howells 已提交
315
static void empress_signal_update(struct work_struct *work)
L
Linus Torvalds 已提交
316
{
D
David Howells 已提交
317 318
	struct saa7134_dev* dev =
		container_of(work, struct saa7134_dev, empress_workqueue);
L
Linus Torvalds 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331

	if (dev->nosignal) {
		dprintk("no video signal\n");
	} else {
		dprintk("video signal acquired\n");
	}
}

static void empress_signal_change(struct saa7134_dev *dev)
{
	schedule_work(&dev->empress_workqueue);
}

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl)
{
	switch (ctrl->id) {
	case V4L2_CID_BRIGHTNESS:
	case V4L2_CID_HUE:
	case V4L2_CID_CONTRAST:
	case V4L2_CID_SATURATION:
	case V4L2_CID_AUDIO_MUTE:
	case V4L2_CID_AUDIO_VOLUME:
	case V4L2_CID_PRIVATE_INVERT:
	case V4L2_CID_PRIVATE_AUTOMUTE:
		return true;
	default:
		return false;
	}
}
L
Linus Torvalds 已提交
348 349 350

static int empress_init(struct saa7134_dev *dev)
{
351
	struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler;
L
Linus Torvalds 已提交
352 353
	int err;

354
	dprintk("%s: %s\n",dev->name,__func__);
L
Linus Torvalds 已提交
355 356 357 358
	dev->empress_dev = video_device_alloc();
	if (NULL == dev->empress_dev)
		return -ENOMEM;
	*(dev->empress_dev) = saa7134_empress_template;
359
	dev->empress_dev->v4l2_dev  = &dev->v4l2_dev;
L
Linus Torvalds 已提交
360 361 362 363
	dev->empress_dev->release = video_device_release;
	snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
		 "%s empress (%s)", dev->name,
		 saa7134_boards[dev->board].name);
364 365 366 367 368 369 370 371 372
	v4l2_ctrl_handler_init(hdl, 21);
	v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter);
	if (dev->empress_sd)
		v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL);
	if (hdl->error) {
		video_device_release(dev->empress_dev);
		return hdl->error;
	}
	dev->empress_dev->ctrl_handler = hdl;
L
Linus Torvalds 已提交
373

D
David Howells 已提交
374
	INIT_WORK(&dev->empress_workqueue, empress_signal_update);
L
Linus Torvalds 已提交
375

376
	video_set_drvdata(dev->empress_dev, dev);
L
Linus Torvalds 已提交
377 378 379 380 381 382 383 384 385
	err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
				    empress_nr[dev->nr]);
	if (err < 0) {
		printk(KERN_INFO "%s: can't register video device\n",
		       dev->name);
		video_device_release(dev->empress_dev);
		dev->empress_dev = NULL;
		return err;
	}
386 387
	printk(KERN_INFO "%s: registered device %s [mpeg]\n",
	       dev->name, video_device_node_name(dev->empress_dev));
L
Linus Torvalds 已提交
388

389 390
	videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops,
			    &dev->pci->dev, &dev->slock,
L
Linus Torvalds 已提交
391 392 393
			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
			    V4L2_FIELD_ALTERNATE,
			    sizeof(struct saa7134_buf),
394
			    dev, NULL);
L
Linus Torvalds 已提交
395

D
David Howells 已提交
396
	empress_signal_update(&dev->empress_workqueue);
L
Linus Torvalds 已提交
397 398 399 400 401
	return 0;
}

static int empress_fini(struct saa7134_dev *dev)
{
402
	dprintk("%s: %s\n",dev->name,__func__);
L
Linus Torvalds 已提交
403 404 405

	if (NULL == dev->empress_dev)
		return 0;
406
	flush_work(&dev->empress_workqueue);
L
Linus Torvalds 已提交
407
	video_unregister_device(dev->empress_dev);
408
	v4l2_ctrl_handler_free(&dev->empress_ctrl_handler);
L
Linus Torvalds 已提交
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
	dev->empress_dev = NULL;
	return 0;
}

static struct saa7134_mpeg_ops empress_ops = {
	.type          = SAA7134_MPEG_EMPRESS,
	.init          = empress_init,
	.fini          = empress_fini,
	.signal_change = empress_signal_change,
};

static int __init empress_register(void)
{
	return saa7134_ts_register(&empress_ops);
}

static void __exit empress_unregister(void)
{
	saa7134_ts_unregister(&empress_ops);
}

module_init(empress_register);
module_exit(empress_unregister);

/* ----------------------------------------------------------- */
/*
 * Local variables:
 * c-basic-offset: 8
 * End:
 */