0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <linux/module.h> /* Modules */
0043 #include <linux/init.h> /* Initdata */
0044 #include <linux/ioport.h> /* request_region */
0045 #include <linux/delay.h> /* udelay, msleep */
0046 #include <linux/videodev2.h> /* kernel radio structs */
0047 #include <linux/mutex.h>
0048 #include <linux/io.h> /* outb, outb_p */
0049 #include <linux/slab.h>
0050 #include <media/v4l2-device.h>
0051 #include <media/v4l2-ioctl.h>
0052 #include "radio-isa.h"
0053
0054 MODULE_AUTHOR("C. van Schaik");
0055 MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
0056 MODULE_LICENSE("GPL");
0057 MODULE_VERSION("0.1.99");
0058
0059 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
0060 #define CONFIG_RADIO_ZOLTRIX_PORT -1
0061 #endif
0062
0063 #define ZOLTRIX_MAX 2
0064
0065 static int io[ZOLTRIX_MAX] = { [0] = CONFIG_RADIO_ZOLTRIX_PORT,
0066 [1 ... (ZOLTRIX_MAX - 1)] = -1 };
0067 static int radio_nr[ZOLTRIX_MAX] = { [0 ... (ZOLTRIX_MAX - 1)] = -1 };
0068
0069 module_param_array(io, int, NULL, 0444);
0070 MODULE_PARM_DESC(io, "I/O addresses of the Zoltrix Radio Plus card (0x20c or 0x30c)");
0071 module_param_array(radio_nr, int, NULL, 0444);
0072 MODULE_PARM_DESC(radio_nr, "Radio device numbers");
0073
0074 struct zoltrix {
0075 struct radio_isa_card isa;
0076 int curvol;
0077 bool muted;
0078 };
0079
0080 static struct radio_isa_card *zoltrix_alloc(void)
0081 {
0082 struct zoltrix *zol = kzalloc(sizeof(*zol), GFP_KERNEL);
0083
0084 return zol ? &zol->isa : NULL;
0085 }
0086
0087 static int zoltrix_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
0088 {
0089 struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
0090
0091 zol->curvol = vol;
0092 zol->muted = mute;
0093 if (mute || vol == 0) {
0094 outb(0, isa->io);
0095 outb(0, isa->io);
0096 inb(isa->io + 3);
0097 return 0;
0098 }
0099
0100 outb(vol - 1, isa->io);
0101 msleep(10);
0102 inb(isa->io + 2);
0103 return 0;
0104 }
0105
0106
0107 static int zoltrix_s_frequency(struct radio_isa_card *isa, u32 freq)
0108 {
0109 struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
0110 struct v4l2_device *v4l2_dev = &isa->v4l2_dev;
0111 unsigned long long bitmask, f, m;
0112 bool stereo = isa->stereo;
0113 int i;
0114
0115 if (freq == 0) {
0116 v4l2_warn(v4l2_dev, "cannot set a frequency of 0.\n");
0117 return -EINVAL;
0118 }
0119
0120 m = (freq / 160 - 8800) * 2;
0121 f = (unsigned long long)m + 0x4d1c;
0122
0123 bitmask = 0xc480402c10080000ull;
0124 i = 45;
0125
0126 outb(0, isa->io);
0127 outb(0, isa->io);
0128 inb(isa->io + 3);
0129
0130 outb(0x40, isa->io);
0131 outb(0xc0, isa->io);
0132
0133 bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31));
0134 while (i--) {
0135 if ((bitmask & 0x8000000000000000ull) != 0) {
0136 outb(0x80, isa->io);
0137 udelay(50);
0138 outb(0x00, isa->io);
0139 udelay(50);
0140 outb(0x80, isa->io);
0141 udelay(50);
0142 } else {
0143 outb(0xc0, isa->io);
0144 udelay(50);
0145 outb(0x40, isa->io);
0146 udelay(50);
0147 outb(0xc0, isa->io);
0148 udelay(50);
0149 }
0150 bitmask *= 2;
0151 }
0152
0153 outb(0x80, isa->io);
0154 outb(0xc0, isa->io);
0155 outb(0x40, isa->io);
0156 udelay(1000);
0157 inb(isa->io + 2);
0158 udelay(1000);
0159
0160 return zoltrix_s_mute_volume(isa, zol->muted, zol->curvol);
0161 }
0162
0163
0164 static u32 zoltrix_g_rxsubchans(struct radio_isa_card *isa)
0165 {
0166 struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
0167 int a, b;
0168
0169 outb(0x00, isa->io);
0170 outb(zol->curvol, isa->io);
0171 msleep(20);
0172
0173 a = inb(isa->io);
0174 msleep(10);
0175 b = inb(isa->io);
0176
0177 return (a == b && a == 0xcf) ?
0178 V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
0179 }
0180
0181 static u32 zoltrix_g_signal(struct radio_isa_card *isa)
0182 {
0183 struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
0184 int a, b;
0185
0186 outb(0x00, isa->io);
0187 outb(zol->curvol, isa->io);
0188 msleep(20);
0189
0190 a = inb(isa->io);
0191 msleep(10);
0192 b = inb(isa->io);
0193
0194 if (a != b)
0195 return 0;
0196
0197
0198 return (a == 0xcf || a == 0xdf || a == 0xef) ? 0xffff : 0;
0199 }
0200
0201 static int zoltrix_s_stereo(struct radio_isa_card *isa, bool stereo)
0202 {
0203 return zoltrix_s_frequency(isa, isa->freq);
0204 }
0205
0206 static const struct radio_isa_ops zoltrix_ops = {
0207 .alloc = zoltrix_alloc,
0208 .s_mute_volume = zoltrix_s_mute_volume,
0209 .s_frequency = zoltrix_s_frequency,
0210 .s_stereo = zoltrix_s_stereo,
0211 .g_rxsubchans = zoltrix_g_rxsubchans,
0212 .g_signal = zoltrix_g_signal,
0213 };
0214
0215 static const int zoltrix_ioports[] = { 0x20c, 0x30c };
0216
0217 static struct radio_isa_driver zoltrix_driver = {
0218 .driver = {
0219 .match = radio_isa_match,
0220 .probe = radio_isa_probe,
0221 .remove = radio_isa_remove,
0222 .driver = {
0223 .name = "radio-zoltrix",
0224 },
0225 },
0226 .io_params = io,
0227 .radio_nr_params = radio_nr,
0228 .io_ports = zoltrix_ioports,
0229 .num_of_io_ports = ARRAY_SIZE(zoltrix_ioports),
0230 .region_size = 2,
0231 .card = "Zoltrix Radio Plus",
0232 .ops = &zoltrix_ops,
0233 .has_stereo = true,
0234 .max_volume = 15,
0235 };
0236
0237 static int __init zoltrix_init(void)
0238 {
0239 return isa_register_driver(&zoltrix_driver.driver, ZOLTRIX_MAX);
0240 }
0241
0242 static void __exit zoltrix_exit(void)
0243 {
0244 isa_unregister_driver(&zoltrix_driver.driver);
0245 }
0246
0247 module_init(zoltrix_init);
0248 module_exit(zoltrix_exit);
0249