Linux 2.6.17.7
[linux/fpc-iii.git] / drivers / media / radio / miropcm20-rds-core.c
blobb602c73e2309ea9cf3313f225d32628599175025
1 /*
2 * Many thanks to Fred Seidel <seidel@metabox.de>, the
3 * designer of the RDS decoder hardware. With his help
4 * I was able to code this driver.
5 * Thanks also to Norberto Pellicci, Dominic Mounteney
6 * <DMounteney@pinnaclesys.com> and www.teleauskunft.de
7 * for good hints on finding Fred. It was somewhat hard
8 * to locate him here in Germany... [:
10 * Revision history:
12 * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de>
13 * RDS support for MiroSound PCM20 radio
16 #include <linux/module.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
19 #include <linux/init.h>
20 #include <linux/slab.h>
21 #include <linux/mutex.h>
23 #include <asm/io.h>
24 #include "../../../sound/oss/aci.h"
25 #include "miropcm20-rds-core.h"
27 #define DEBUG 0
29 static struct mutex aci_rds_mutex;
31 #define RDS_DATASHIFT 2 /* Bit 2 */
32 #define RDS_DATAMASK (1 << RDS_DATASHIFT)
33 #define RDS_BUSYMASK 0x10 /* Bit 4 */
34 #define RDS_CLOCKMASK 0x08 /* Bit 3 */
36 #define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
39 #if DEBUG
40 static void print_matrix(char array[], unsigned int length)
42 int i, j;
44 for (i=0; i<length; i++) {
45 printk(KERN_DEBUG "aci-rds: ");
46 for (j=7; j>=0; j--) {
47 printk("%d", (array[i] >> j) & 0x1);
49 if (i%8 == 0)
50 printk(" byte-border\n");
51 else
52 printk("\n");
55 #endif /* DEBUG */
57 static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
59 int i;
61 if (size != 8)
62 return -1;
63 for (i = 7; i >= 0; i--)
64 sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
65 sendbuffer[0] |= RDS_CLOCKMASK;
67 return 0;
70 static int rds_waitread(void)
72 unsigned char byte;
73 int i=2000;
75 do {
76 byte=inb(RDS_REGISTER);
77 i--;
79 while ((byte & RDS_BUSYMASK) && i);
81 if (i) {
82 #if DEBUG
83 printk(KERN_DEBUG "rds_waitread()");
84 print_matrix(&byte, 1);
85 #endif
86 return (byte);
87 } else {
88 printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n");
89 return -1;
93 /* don't use any ..._nowait() function if you are not sure what you do... */
95 static inline void rds_rawwrite_nowait(unsigned char byte)
97 #if DEBUG
98 printk(KERN_DEBUG "rds_rawwrite()");
99 print_matrix(&byte, 1);
100 #endif
101 outb(byte, RDS_REGISTER);
104 static int rds_rawwrite(unsigned char byte)
106 if (rds_waitread() >= 0) {
107 rds_rawwrite_nowait(byte);
108 return 0;
109 } else
110 return -1;
113 static int rds_write(unsigned char cmd)
115 unsigned char sendbuffer[8];
116 int i;
118 if (byte2trans(cmd, sendbuffer, 8) != 0){
119 return -1;
120 } else {
121 for (i=0; i<8; i++) {
122 rds_rawwrite(sendbuffer[i]);
125 return 0;
128 static int rds_readcycle_nowait(void)
130 rds_rawwrite_nowait(0);
131 return rds_waitread();
134 static int rds_readcycle(void)
136 if (rds_rawwrite(0) < 0)
137 return -1;
138 return rds_waitread();
141 static int rds_read(unsigned char databuffer[], int datasize)
143 #define READSIZE (8*datasize)
145 int i,j;
147 if (datasize < 1) /* nothing to read */
148 return 0;
150 /* to be able to use rds_readcycle_nowait()
151 I have to waitread() here */
152 if (rds_waitread() < 0)
153 return -1;
155 memset(databuffer, 0, datasize);
157 for (i=0; i< READSIZE; i++)
158 if((j=rds_readcycle_nowait()) < 0) {
159 return -1;
160 } else {
161 databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8)));
164 return 0;
167 static int rds_ack(void)
169 int i=rds_readcycle();
171 if (i < 0)
172 return -1;
173 if (i & RDS_DATAMASK) {
174 return 0; /* ACK */
175 } else {
176 printk(KERN_DEBUG "aci-rds: NACK\n");
177 return 1; /* NACK */
181 int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
183 int ret;
185 if (mutex_lock_interruptible(&aci_rds_mutex))
186 return -EINTR;
188 rds_write(cmd);
190 /* RDS_RESET doesn't need further processing */
191 if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
192 ret = -1;
193 else
194 ret = 0;
196 mutex_unlock(&aci_rds_mutex);
198 return ret;
200 EXPORT_SYMBOL(aci_rds_cmd);
202 int __init attach_aci_rds(void)
204 mutex_init(&aci_rds_mutex);
205 return 0;
208 void __exit unload_aci_rds(void)
211 MODULE_LICENSE("GPL");