xref: /linux/drivers/media/radio/radio-miropcm20.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * Miro PCM20 radio driver for Linux radio support
3  * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
4  * Thanks to Norberto Pellici for the ACI device interface specification
5  * The API part is based on the radiotrack driver by M. Kirkwood
6  * This driver relies on the aci mixer provided by the snd-miro
7  * ALSA driver.
8  * Look there for further info...
9  *
10  * From the original miro RDS sources:
11  *
12  *  (c) 2001 Robert Siemer <Robert.Siemer@gmx.de>
13  *
14  *  Many thanks to Fred Seidel <seidel@metabox.de>, the
15  *  designer of the RDS decoder hardware. With his help
16  *  I was able to code this driver.
17  *  Thanks also to Norberto Pellicci, Dominic Mounteney
18  *  <DMounteney@pinnaclesys.com> and www.teleauskunft.de
19  *  for good hints on finding Fred. It was somewhat hard
20  *  to locate him here in Germany... [:
21  *
22  * This code has been reintroduced and converted to use
23  * the new V4L2 RDS API by:
24  *
25  * Hans Verkuil <hans.verkuil@cisco.com>
26  */
27 
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/io.h>
31 #include <linux/delay.h>
32 #include <linux/videodev2.h>
33 #include <linux/kthread.h>
34 #include <media/v4l2-device.h>
35 #include <media/v4l2-ioctl.h>
36 #include <media/v4l2-ctrls.h>
37 #include <media/v4l2-fh.h>
38 #include <media/v4l2-event.h>
39 #include <sound/aci.h>
40 
41 #define RDS_DATASHIFT          2   /* Bit 2 */
42 #define RDS_DATAMASK        (1 << RDS_DATASHIFT)
43 #define RDS_BUSYMASK        0x10   /* Bit 4 */
44 #define RDS_CLOCKMASK       0x08   /* Bit 3 */
45 #define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1)
46 
47 #define RDS_STATUS      0x01
48 #define RDS_STATIONNAME 0x02
49 #define RDS_TEXT        0x03
50 #define RDS_ALTFREQ     0x04
51 #define RDS_TIMEDATE    0x05
52 #define RDS_PI_CODE     0x06
53 #define RDS_PTYTATP     0x07
54 #define RDS_RESET       0x08
55 #define RDS_RXVALUE     0x09
56 
57 static int radio_nr = -1;
58 module_param(radio_nr, int, 0);
59 MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX).  Default: -1 (autodetect)");
60 
61 struct pcm20 {
62 	struct v4l2_device v4l2_dev;
63 	struct video_device vdev;
64 	struct v4l2_ctrl_handler ctrl_handler;
65 	struct v4l2_ctrl *rds_pty;
66 	struct v4l2_ctrl *rds_ps_name;
67 	struct v4l2_ctrl *rds_radio_test;
68 	struct v4l2_ctrl *rds_ta;
69 	struct v4l2_ctrl *rds_tp;
70 	struct v4l2_ctrl *rds_ms;
71 	/* thread for periodic RDS status checking */
72 	struct task_struct *kthread;
73 	unsigned long freq;
74 	u32 audmode;
75 	struct snd_miro_aci *aci;
76 	struct mutex lock;
77 };
78 
79 static struct pcm20 pcm20_card = {
80 	.freq = 87 * 16000,
81 	.audmode = V4L2_TUNER_MODE_STEREO,
82 };
83 
84 
85 static int rds_waitread(struct snd_miro_aci *aci)
86 {
87 	u8 byte;
88 	int i = 2000;
89 
90 	do {
91 		byte = inb(aci->aci_port + ACI_REG_RDS);
92 		i--;
93 	} while ((byte & RDS_BUSYMASK) && i);
94 
95 	/*
96 	 * It's magic, but without this the data that you read later on
97 	 * is unreliable and full of bit errors. With this 1 usec delay
98 	 * everything is fine.
99 	 */
100 	udelay(1);
101 	return i ? byte : -1;
102 }
103 
104 static int rds_rawwrite(struct snd_miro_aci *aci, u8 byte)
105 {
106 	if (rds_waitread(aci) >= 0) {
107 		outb(byte, aci->aci_port + ACI_REG_RDS);
108 		return 0;
109 	}
110 	return -1;
111 }
112 
113 static int rds_write(struct snd_miro_aci *aci, u8 byte)
114 {
115 	u8 sendbuffer[8];
116 	int i;
117 
118 	for (i = 7; i >= 0; i--)
119 		sendbuffer[7 - i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
120 	sendbuffer[0] |= RDS_CLOCKMASK;
121 
122 	for (i = 0; i < 8; i++)
123 		rds_rawwrite(aci, sendbuffer[i]);
124 	return 0;
125 }
126 
127 static int rds_readcycle_nowait(struct snd_miro_aci *aci)
128 {
129 	outb(0, aci->aci_port + ACI_REG_RDS);
130 	return rds_waitread(aci);
131 }
132 
133 static int rds_readcycle(struct snd_miro_aci *aci)
134 {
135 	if (rds_rawwrite(aci, 0) < 0)
136 		return -1;
137 	return rds_waitread(aci);
138 }
139 
140 static int rds_ack(struct snd_miro_aci *aci)
141 {
142 	int i = rds_readcycle(aci);
143 
144 	if (i < 0)
145 		return -1;
146 	if (i & RDS_DATAMASK)
147 		return 0;  /* ACK  */
148 	return 1;  /* NACK */
149 }
150 
151 static int rds_cmd(struct snd_miro_aci *aci, u8 cmd, u8 databuffer[], u8 datasize)
152 {
153 	int i, j;
154 
155 	rds_write(aci, cmd);
156 
157 	/* RDS_RESET doesn't need further processing */
158 	if (cmd == RDS_RESET)
159 		return 0;
160 	if (rds_ack(aci))
161 		return -EIO;
162 	if (datasize == 0)
163 		return 0;
164 
165 	/* to be able to use rds_readcycle_nowait()
166 	   I have to waitread() here */
167 	if (rds_waitread(aci) < 0)
168 		return -1;
169 
170 	memset(databuffer, 0, datasize);
171 
172 	for (i = 0; i < 8 * datasize; i++) {
173 		j = rds_readcycle_nowait(aci);
174 		if (j < 0)
175 			return -EIO;
176 		databuffer[i / 8] |= RDS_DATA(j) << (7 - (i % 8));
177 	}
178 	return 0;
179 }
180 
181 static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
182 {
183 	unsigned char freql;
184 	unsigned char freqh;
185 	struct snd_miro_aci *aci = dev->aci;
186 
187 	freq /= 160;
188 	if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0))
189 		freq /= 10;  /* I don't know exactly which version
190 			      * needs this hack */
191 	freql = freq & 0xff;
192 	freqh = freq >> 8;
193 
194 	rds_cmd(aci, RDS_RESET, NULL, 0);
195 	return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh);
196 }
197 
198 static int vidioc_querycap(struct file *file, void *priv,
199 				struct v4l2_capability *v)
200 {
201 	struct pcm20 *dev = video_drvdata(file);
202 
203 	strlcpy(v->driver, "Miro PCM20", sizeof(v->driver));
204 	strlcpy(v->card, "Miro PCM20", sizeof(v->card));
205 	snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name);
206 	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
207 	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
208 	return 0;
209 }
210 
211 static bool sanitize(char *p, int size)
212 {
213 	int i;
214 	bool ret = true;
215 
216 	for (i = 0; i < size; i++) {
217 		if (p[i] < 32) {
218 			p[i] = ' ';
219 			ret = false;
220 		}
221 	}
222 	return ret;
223 }
224 
225 static int vidioc_g_tuner(struct file *file, void *priv,
226 				struct v4l2_tuner *v)
227 {
228 	struct pcm20 *dev = video_drvdata(file);
229 	int res;
230 	u8 buf;
231 
232 	if (v->index)
233 		return -EINVAL;
234 	strlcpy(v->name, "FM", sizeof(v->name));
235 	v->type = V4L2_TUNER_RADIO;
236 	v->rangelow = 87*16000;
237 	v->rangehigh = 108*16000;
238 	res = snd_aci_cmd(dev->aci, ACI_READ_TUNERSTATION, -1, -1);
239 	v->signal = (res & 0x80) ? 0 : 0xffff;
240 	/* Note: stereo detection does not work if the audio is muted,
241 	   it will default to mono in that case. */
242 	res = snd_aci_cmd(dev->aci, ACI_READ_TUNERSTEREO, -1, -1);
243 	v->rxsubchans = (res & 0x40) ? V4L2_TUNER_SUB_MONO :
244 					V4L2_TUNER_SUB_STEREO;
245 	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
246 			V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS;
247 	v->audmode = dev->audmode;
248 	res = rds_cmd(dev->aci, RDS_RXVALUE, &buf, 1);
249 	if (res >= 0 && buf)
250 		v->rxsubchans |= V4L2_TUNER_SUB_RDS;
251 	return 0;
252 }
253 
254 static int vidioc_s_tuner(struct file *file, void *priv,
255 				const struct v4l2_tuner *v)
256 {
257 	struct pcm20 *dev = video_drvdata(file);
258 
259 	if (v->index)
260 		return -EINVAL;
261 	if (v->audmode > V4L2_TUNER_MODE_STEREO)
262 		dev->audmode = V4L2_TUNER_MODE_STEREO;
263 	else
264 		dev->audmode = v->audmode;
265 	snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
266 			dev->audmode == V4L2_TUNER_MODE_MONO, -1);
267 	return 0;
268 }
269 
270 static int vidioc_g_frequency(struct file *file, void *priv,
271 				struct v4l2_frequency *f)
272 {
273 	struct pcm20 *dev = video_drvdata(file);
274 
275 	if (f->tuner != 0)
276 		return -EINVAL;
277 
278 	f->type = V4L2_TUNER_RADIO;
279 	f->frequency = dev->freq;
280 	return 0;
281 }
282 
283 
284 static int vidioc_s_frequency(struct file *file, void *priv,
285 				const struct v4l2_frequency *f)
286 {
287 	struct pcm20 *dev = video_drvdata(file);
288 
289 	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
290 		return -EINVAL;
291 
292 	dev->freq = clamp_t(u32, f->frequency, 87 * 16000U, 108 * 16000U);
293 	pcm20_setfreq(dev, dev->freq);
294 	return 0;
295 }
296 
297 static int pcm20_s_ctrl(struct v4l2_ctrl *ctrl)
298 {
299 	struct pcm20 *dev = container_of(ctrl->handler, struct pcm20, ctrl_handler);
300 
301 	switch (ctrl->id) {
302 	case V4L2_CID_AUDIO_MUTE:
303 		snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, ctrl->val, -1);
304 		return 0;
305 	}
306 	return -EINVAL;
307 }
308 
309 static int pcm20_thread(void *data)
310 {
311 	struct pcm20 *dev = data;
312 	const unsigned no_rds_start_counter = 5;
313 	const unsigned sleep_msecs = 2000;
314 	unsigned no_rds_counter = no_rds_start_counter;
315 
316 	for (;;) {
317 		char text_buffer[66];
318 		u8 buf;
319 		int res;
320 
321 		msleep_interruptible(sleep_msecs);
322 
323 		if (kthread_should_stop())
324 			break;
325 
326 		res = rds_cmd(dev->aci, RDS_RXVALUE, &buf, 1);
327 		if (res)
328 			continue;
329 		if (buf == 0) {
330 			if (no_rds_counter == 0)
331 				continue;
332 			no_rds_counter--;
333 			if (no_rds_counter)
334 				continue;
335 
336 			/*
337 			 * No RDS seen for no_rds_start_counter * sleep_msecs
338 			 * milliseconds, clear all RDS controls to their
339 			 * default values.
340 			 */
341 			v4l2_ctrl_s_ctrl_string(dev->rds_ps_name, "");
342 			v4l2_ctrl_s_ctrl(dev->rds_ms, 1);
343 			v4l2_ctrl_s_ctrl(dev->rds_ta, 0);
344 			v4l2_ctrl_s_ctrl(dev->rds_tp, 0);
345 			v4l2_ctrl_s_ctrl(dev->rds_pty, 0);
346 			v4l2_ctrl_s_ctrl_string(dev->rds_radio_test, "");
347 			continue;
348 		}
349 		no_rds_counter = no_rds_start_counter;
350 
351 		res = rds_cmd(dev->aci, RDS_STATUS, &buf, 1);
352 		if (res)
353 			continue;
354 		if ((buf >> 3) & 1) {
355 			res = rds_cmd(dev->aci, RDS_STATIONNAME, text_buffer, 8);
356 			text_buffer[8] = 0;
357 			if (!res && sanitize(text_buffer, 8))
358 				v4l2_ctrl_s_ctrl_string(dev->rds_ps_name, text_buffer);
359 		}
360 		if ((buf >> 6) & 1) {
361 			u8 pty;
362 
363 			res = rds_cmd(dev->aci, RDS_PTYTATP, &pty, 1);
364 			if (!res) {
365 				v4l2_ctrl_s_ctrl(dev->rds_ms, !!(pty & 0x01));
366 				v4l2_ctrl_s_ctrl(dev->rds_ta, !!(pty & 0x02));
367 				v4l2_ctrl_s_ctrl(dev->rds_tp, !!(pty & 0x80));
368 				v4l2_ctrl_s_ctrl(dev->rds_pty, (pty >> 2) & 0x1f);
369 			}
370 		}
371 		if ((buf >> 4) & 1) {
372 			res = rds_cmd(dev->aci, RDS_TEXT, text_buffer, 65);
373 			text_buffer[65] = 0;
374 			if (!res && sanitize(text_buffer + 1, 64))
375 				v4l2_ctrl_s_ctrl_string(dev->rds_radio_test, text_buffer + 1);
376 		}
377 	}
378 	return 0;
379 }
380 
381 static int pcm20_open(struct file *file)
382 {
383 	struct pcm20 *dev = video_drvdata(file);
384 	int res = v4l2_fh_open(file);
385 
386 	if (!res && v4l2_fh_is_singular_file(file) &&
387 	    IS_ERR_OR_NULL(dev->kthread)) {
388 		dev->kthread = kthread_run(pcm20_thread, dev, "%s",
389 					   dev->v4l2_dev.name);
390 		if (IS_ERR(dev->kthread)) {
391 			v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
392 			v4l2_fh_release(file);
393 			return PTR_ERR(dev->kthread);
394 		}
395 	}
396 	return res;
397 }
398 
399 static int pcm20_release(struct file *file)
400 {
401 	struct pcm20 *dev = video_drvdata(file);
402 
403 	if (v4l2_fh_is_singular_file(file) && !IS_ERR_OR_NULL(dev->kthread)) {
404 		kthread_stop(dev->kthread);
405 		dev->kthread = NULL;
406 	}
407 	return v4l2_fh_release(file);
408 }
409 
410 static const struct v4l2_file_operations pcm20_fops = {
411 	.owner		= THIS_MODULE,
412 	.open		= pcm20_open,
413 	.poll		= v4l2_ctrl_poll,
414 	.release	= pcm20_release,
415 	.unlocked_ioctl	= video_ioctl2,
416 };
417 
418 static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
419 	.vidioc_querycap    = vidioc_querycap,
420 	.vidioc_g_tuner     = vidioc_g_tuner,
421 	.vidioc_s_tuner     = vidioc_s_tuner,
422 	.vidioc_g_frequency = vidioc_g_frequency,
423 	.vidioc_s_frequency = vidioc_s_frequency,
424 	.vidioc_log_status  = v4l2_ctrl_log_status,
425 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
426 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
427 };
428 
429 static const struct v4l2_ctrl_ops pcm20_ctrl_ops = {
430 	.s_ctrl = pcm20_s_ctrl,
431 };
432 
433 static int __init pcm20_init(void)
434 {
435 	struct pcm20 *dev = &pcm20_card;
436 	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
437 	struct v4l2_ctrl_handler *hdl;
438 	int res;
439 
440 	dev->aci = snd_aci_get_aci();
441 	if (dev->aci == NULL) {
442 		v4l2_err(v4l2_dev,
443 			 "you must load the snd-miro driver first!\n");
444 		return -ENODEV;
445 	}
446 	strlcpy(v4l2_dev->name, "radio-miropcm20", sizeof(v4l2_dev->name));
447 	mutex_init(&dev->lock);
448 
449 	res = v4l2_device_register(NULL, v4l2_dev);
450 	if (res < 0) {
451 		v4l2_err(v4l2_dev, "could not register v4l2_device\n");
452 		return -EINVAL;
453 	}
454 
455 	hdl = &dev->ctrl_handler;
456 	v4l2_ctrl_handler_init(hdl, 7);
457 	v4l2_ctrl_new_std(hdl, &pcm20_ctrl_ops,
458 			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
459 	dev->rds_pty = v4l2_ctrl_new_std(hdl, NULL,
460 			V4L2_CID_RDS_RX_PTY, 0, 0x1f, 1, 0);
461 	dev->rds_ps_name = v4l2_ctrl_new_std(hdl, NULL,
462 			V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0);
463 	dev->rds_radio_test = v4l2_ctrl_new_std(hdl, NULL,
464 			V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0);
465 	dev->rds_ta = v4l2_ctrl_new_std(hdl, NULL,
466 			V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
467 	dev->rds_tp = v4l2_ctrl_new_std(hdl, NULL,
468 			V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
469 	dev->rds_ms = v4l2_ctrl_new_std(hdl, NULL,
470 			V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1);
471 	v4l2_dev->ctrl_handler = hdl;
472 	if (hdl->error) {
473 		res = hdl->error;
474 		v4l2_err(v4l2_dev, "Could not register control\n");
475 		goto err_hdl;
476 	}
477 	strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
478 	dev->vdev.v4l2_dev = v4l2_dev;
479 	dev->vdev.fops = &pcm20_fops;
480 	dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
481 	dev->vdev.release = video_device_release_empty;
482 	dev->vdev.lock = &dev->lock;
483 	video_set_drvdata(&dev->vdev, dev);
484 	snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
485 			dev->audmode == V4L2_TUNER_MODE_MONO, -1);
486 	pcm20_setfreq(dev, dev->freq);
487 
488 	if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
489 		goto err_hdl;
490 
491 	v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n");
492 	return 0;
493 err_hdl:
494 	v4l2_ctrl_handler_free(hdl);
495 	v4l2_device_unregister(v4l2_dev);
496 	return -EINVAL;
497 }
498 
499 MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt");
500 MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
501 MODULE_LICENSE("GPL");
502 
503 static void __exit pcm20_cleanup(void)
504 {
505 	struct pcm20 *dev = &pcm20_card;
506 
507 	video_unregister_device(&dev->vdev);
508 	snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, 1, -1);
509 	v4l2_ctrl_handler_free(&dev->ctrl_handler);
510 	v4l2_device_unregister(&dev->v4l2_dev);
511 }
512 
513 module_init(pcm20_init);
514 module_exit(pcm20_cleanup);
515