[go: nahoru, domu]

13088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil/*
23088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil * radio-aztech.c - Aztech radio card driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
43088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@xs4all.nl>
5a4366af40d7d2021499b84b8311336c944a9a71cMauro Carvalho Chehab * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
64286c6f65ec01efa8f5108cadea402ecf3b12279Mauro Carvalho Chehab * Adapted to support the Video for Linux API by
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Quay Ly
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Donald Song
114286c6f65ec01efa8f5108cadea402ecf3b12279Mauro Carvalho Chehab * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
153088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>	/* Modules 			*/
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>		/* Initdata			*/
20fb911ee849756fc6c609dddded92d9207ff3fb29Peter Osterlund#include <linux/ioport.h>	/* request_region		*/
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>	/* udelay			*/
22a4366af40d7d2021499b84b8311336c944a9a71cMauro Carvalho Chehab#include <linux/videodev2.h>	/* kernel radio structs		*/
23e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuil#include <linux/io.h>		/* outb, outb_p			*/
249f1dfccf6607822f556698f0940ead57e6e42d5fHans Verkuil#include <linux/slab.h>
25e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuil#include <media/v4l2-device.h>
2635ea11ff84719b1bfab2909903a9640a86552fd1Hans Verkuil#include <media/v4l2-ioctl.h>
273088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil#include <media/v4l2-ctrls.h>
283088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil#include "radio-isa.h"
29eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary#include "lm7000.h"
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31e697e12ecede8ee4f5beb11ed4981d7254be0125Hans VerkuilMODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
32e697e12ecede8ee4f5beb11ed4981d7254be0125Hans VerkuilMODULE_DESCRIPTION("A driver for the Aztech radio card.");
33e697e12ecede8ee4f5beb11ed4981d7254be0125Hans VerkuilMODULE_LICENSE("GPL");
343088fba877ee8bf284b12a73332b813b5478a64dHans VerkuilMODULE_VERSION("1.0.0");
35a4366af40d7d2021499b84b8311336c944a9a71cMauro Carvalho Chehab
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_RADIO_AZTECH_PORT
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG_RADIO_AZTECH_PORT -1
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
413088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil#define AZTECH_MAX 2
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
433088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic int io[AZTECH_MAX] = { [0] = CONFIG_RADIO_AZTECH_PORT,
443088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil			      [1 ... (AZTECH_MAX - 1)] = -1 };
453088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic int radio_nr[AZTECH_MAX]	= { [0 ... (AZTECH_MAX - 1)] = -1 };
463088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic const int radio_wait_time = 1000;
47e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuil
483088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilmodule_param_array(io, int, NULL, 0444);
493088fba877ee8bf284b12a73332b813b5478a64dHans VerkuilMODULE_PARM_DESC(io, "I/O addresses of the Aztech card (0x350 or 0x358)");
503088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilmodule_param_array(radio_nr, int, NULL, 0444);
513088fba877ee8bf284b12a73332b813b5478a64dHans VerkuilMODULE_PARM_DESC(radio_nr, "Radio device numbers");
523088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil
533088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstruct aztech {
543088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	struct radio_isa_card isa;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int curvol;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary/* bit definitions for register read */
59eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary#define AZTECH_BIT_NOT_TUNED	(1 << 0)
60eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary#define AZTECH_BIT_MONO		(1 << 1)
61eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary/* bit definitions for register write */
62eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary#define AZTECH_BIT_TUN_CE	(1 << 1)
63eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary#define AZTECH_BIT_TUN_CLK	(1 << 6)
64eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary#define AZTECH_BIT_TUN_DATA	(1 << 7)
65eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary/* bits 0 and 2 are volume control, bits 3..5 are not connected */
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zarystatic void aztech_set_pins(void *handle, u8 pins)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
69eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	struct radio_isa_card *isa = handle;
70eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	struct aztech *az = container_of(isa, struct aztech, isa);
71eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	u8 bits = az->curvol;
72eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary
73eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	if (pins & LM7000_DATA)
74eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary		bits |= AZTECH_BIT_TUN_DATA;
75eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	if (pins & LM7000_CLK)
76eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary		bits |= AZTECH_BIT_TUN_CLK;
77eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	if (pins & LM7000_CE)
78eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary		bits |= AZTECH_BIT_TUN_CE;
79eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary
80eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	outb_p(bits, az->isa.io);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
833088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic struct radio_isa_card *aztech_alloc(void)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
853088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	struct aztech *az = kzalloc(sizeof(*az), GFP_KERNEL);
86e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuil
873088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	return az ? &az->isa : NULL;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
903088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic int aztech_s_frequency(struct radio_isa_card *isa, u32 freq)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
92eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	lm7000_set_freq(freq, isa, aztech_set_pins);
93676b0ac7aa409d326d92ca46c65bba20bebb3c1cMauro Carvalho Chehab
94a0c05ab9762560cf12733181d19b6529bb7231d2Mauro Carvalho Chehab	return 0;
95a0c05ab9762560cf12733181d19b6529bb7231d2Mauro Carvalho Chehab}
96a0c05ab9762560cf12733181d19b6529bb7231d2Mauro Carvalho Chehab
973088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic u32 aztech_g_rxsubchans(struct radio_isa_card *isa)
98e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuil{
991c9f11ed21816290a7cea36fc2dc3b16d5590340Ondrej Zary	if (inb(isa->io) & AZTECH_BIT_MONO)
1003088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil		return V4L2_TUNER_SUB_MONO;
1013088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	return V4L2_TUNER_SUB_STEREO;
102e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuil}
103e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuil
1041c9f11ed21816290a7cea36fc2dc3b16d5590340Ondrej Zarystatic u32 aztech_g_signal(struct radio_isa_card *isa)
10599218fe478e2ca6d5ee660a655690ab6496e6ab5Mauro Carvalho Chehab{
1061c9f11ed21816290a7cea36fc2dc3b16d5590340Ondrej Zary	return (inb(isa->io) & AZTECH_BIT_NOT_TUNED) ? 0 : 0xffff;
10799218fe478e2ca6d5ee660a655690ab6496e6ab5Mauro Carvalho Chehab}
10899218fe478e2ca6d5ee660a655690ab6496e6ab5Mauro Carvalho Chehab
1093088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic int aztech_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
11099218fe478e2ca6d5ee660a655690ab6496e6ab5Mauro Carvalho Chehab{
1113088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	struct aztech *az = container_of(isa, struct aztech, isa);
11299218fe478e2ca6d5ee660a655690ab6496e6ab5Mauro Carvalho Chehab
1133088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	if (mute)
1143088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil		vol = 0;
1153088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	az->curvol = (vol & 1) + ((vol & 2) << 1);
1163088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	outb(az->curvol, isa->io);
11799218fe478e2ca6d5ee660a655690ab6496e6ab5Mauro Carvalho Chehab	return 0;
11899218fe478e2ca6d5ee660a655690ab6496e6ab5Mauro Carvalho Chehab}
11999218fe478e2ca6d5ee660a655690ab6496e6ab5Mauro Carvalho Chehab
1203088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic const struct radio_isa_ops aztech_ops = {
1213088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.alloc = aztech_alloc,
1223088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.s_mute_volume = aztech_s_mute_volume,
1233088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.s_frequency = aztech_s_frequency,
1243088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.g_rxsubchans = aztech_g_rxsubchans,
1251c9f11ed21816290a7cea36fc2dc3b16d5590340Ondrej Zary	.g_signal = aztech_g_signal,
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1283088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic const int aztech_ioports[] = { 0x350, 0x358 };
1293088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil
1303088fba877ee8bf284b12a73332b813b5478a64dHans Verkuilstatic struct radio_isa_driver aztech_driver = {
1313088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.driver = {
1323088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil		.match		= radio_isa_match,
1333088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil		.probe		= radio_isa_probe,
1343088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil		.remove		= radio_isa_remove,
1353088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil		.driver		= {
1363088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil			.name	= "radio-aztech",
1373088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil		},
1383088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	},
1393088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.io_params = io,
1403088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.radio_nr_params = radio_nr,
1413088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.io_ports = aztech_ioports,
1423088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.num_of_io_ports = ARRAY_SIZE(aztech_ioports),
143eb27fafef69568a82c46c27a1761f037e4272b87Ondrej Zary	.region_size = 8,
1443088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.card = "Aztech Radio",
1453088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.ops = &aztech_ops,
1463088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.has_stereo = true,
1473088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	.max_volume = 3,
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init aztech_init(void)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1523088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	return isa_register_driver(&aztech_driver.driver, AZTECH_MAX);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
155e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuilstatic void __exit aztech_exit(void)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1573088fba877ee8bf284b12a73332b813b5478a64dHans Verkuil	isa_unregister_driver(&aztech_driver.driver);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(aztech_init);
161e697e12ecede8ee4f5beb11ed4981d7254be0125Hans Verkuilmodule_exit(aztech_exit);
162