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 #include <linux/module.h> /* Modules */
0033 #include <linux/init.h> /* Initdata */
0034 #include <linux/ioport.h> /* request_region */
0035 #include <linux/videodev2.h> /* kernel radio structs */
0036 #include <linux/io.h> /* outb, outb_p */
0037 #include <linux/slab.h>
0038 #include <media/v4l2-device.h>
0039 #include <media/v4l2-ioctl.h>
0040 #include "radio-isa.h"
0041
0042 #define DRIVER_VERSION "0.1.2"
0043
0044 MODULE_AUTHOR("Dr. Henrik Seidel");
0045 MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
0046 MODULE_LICENSE("GPL");
0047 MODULE_VERSION("0.1.99");
0048
0049 #ifndef CONFIG_RADIO_TYPHOON_PORT
0050 #define CONFIG_RADIO_TYPHOON_PORT -1
0051 #endif
0052
0053 #ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ
0054 #define CONFIG_RADIO_TYPHOON_MUTEFREQ 87000
0055 #endif
0056
0057 #define TYPHOON_MAX 2
0058
0059 static int io[TYPHOON_MAX] = { [0] = CONFIG_RADIO_TYPHOON_PORT,
0060 [1 ... (TYPHOON_MAX - 1)] = -1 };
0061 static int radio_nr[TYPHOON_MAX] = { [0 ... (TYPHOON_MAX - 1)] = -1 };
0062 static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ;
0063
0064 module_param_array(io, int, NULL, 0444);
0065 MODULE_PARM_DESC(io, "I/O addresses of the Typhoon card (0x316 or 0x336)");
0066 module_param_array(radio_nr, int, NULL, 0444);
0067 MODULE_PARM_DESC(radio_nr, "Radio device numbers");
0068 module_param(mutefreq, ulong, 0);
0069 MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
0070
0071 struct typhoon {
0072 struct radio_isa_card isa;
0073 int muted;
0074 };
0075
0076 static struct radio_isa_card *typhoon_alloc(void)
0077 {
0078 struct typhoon *ty = kzalloc(sizeof(*ty), GFP_KERNEL);
0079
0080 return ty ? &ty->isa : NULL;
0081 }
0082
0083 static int typhoon_s_frequency(struct radio_isa_card *isa, u32 freq)
0084 {
0085 unsigned long outval;
0086 unsigned long x;
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 x = freq / 160;
0100 outval = (x * x + 2500) / 5000;
0101 outval = (outval * x + 5000) / 10000;
0102 outval -= (10 * x * x + 10433) / 20866;
0103 outval += 4 * x - 11505;
0104
0105 outb_p((outval >> 8) & 0x01, isa->io + 4);
0106 outb_p(outval >> 9, isa->io + 6);
0107 outb_p(outval & 0xff, isa->io + 8);
0108 return 0;
0109 }
0110
0111 static int typhoon_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
0112 {
0113 struct typhoon *ty = container_of(isa, struct typhoon, isa);
0114
0115 if (mute)
0116 vol = 0;
0117 vol >>= 14;
0118 vol &= 3;
0119 outb_p(vol / 2, isa->io);
0120 outb_p(vol % 2, isa->io + 2);
0121
0122 if (vol == 0 && !ty->muted) {
0123 ty->muted = true;
0124 return typhoon_s_frequency(isa, mutefreq << 4);
0125 }
0126 if (vol && ty->muted) {
0127 ty->muted = false;
0128 return typhoon_s_frequency(isa, isa->freq);
0129 }
0130 return 0;
0131 }
0132
0133 static const struct radio_isa_ops typhoon_ops = {
0134 .alloc = typhoon_alloc,
0135 .s_mute_volume = typhoon_s_mute_volume,
0136 .s_frequency = typhoon_s_frequency,
0137 };
0138
0139 static const int typhoon_ioports[] = { 0x316, 0x336 };
0140
0141 static struct radio_isa_driver typhoon_driver = {
0142 .driver = {
0143 .match = radio_isa_match,
0144 .probe = radio_isa_probe,
0145 .remove = radio_isa_remove,
0146 .driver = {
0147 .name = "radio-typhoon",
0148 },
0149 },
0150 .io_params = io,
0151 .radio_nr_params = radio_nr,
0152 .io_ports = typhoon_ioports,
0153 .num_of_io_ports = ARRAY_SIZE(typhoon_ioports),
0154 .region_size = 8,
0155 .card = "Typhoon Radio",
0156 .ops = &typhoon_ops,
0157 .has_stereo = true,
0158 .max_volume = 3,
0159 };
0160
0161 static int __init typhoon_init(void)
0162 {
0163 if (mutefreq < 87000 || mutefreq > 108000) {
0164 printk(KERN_ERR "%s: You must set a frequency (in kHz) used when muting the card,\n",
0165 typhoon_driver.driver.driver.name);
0166 printk(KERN_ERR "%s: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108000)\n",
0167 typhoon_driver.driver.driver.name);
0168 return -ENODEV;
0169 }
0170 return isa_register_driver(&typhoon_driver.driver, TYPHOON_MAX);
0171 }
0172
0173 static void __exit typhoon_exit(void)
0174 {
0175 isa_unregister_driver(&typhoon_driver.driver);
0176 }
0177
0178
0179 module_init(typhoon_init);
0180 module_exit(typhoon_exit);
0181