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... [:
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>
24 #include "../../../sound/oss/aci.h"
25 #include "miropcm20-rds-core.h"
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)
40 static void print_matrix(char array
[], unsigned int length
)
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);
50 printk(" byte-border\n");
57 static int byte2trans(unsigned char byte
, unsigned char sendbuffer
[], int size
)
63 for (i
= 7; i
>= 0; i
--)
64 sendbuffer
[7-i
] = (byte
& (1 << i
)) ? RDS_DATAMASK
: 0;
65 sendbuffer
[0] |= RDS_CLOCKMASK
;
70 static int rds_waitread(void)
76 byte
=inb(RDS_REGISTER
);
79 while ((byte
& RDS_BUSYMASK
) && i
);
83 printk(KERN_DEBUG
"rds_waitread()");
84 print_matrix(&byte
, 1);
88 printk(KERN_WARNING
"aci-rds: rds_waitread() timeout...\n");
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
)
98 printk(KERN_DEBUG
"rds_rawwrite()");
99 print_matrix(&byte
, 1);
101 outb(byte
, RDS_REGISTER
);
104 static int rds_rawwrite(unsigned char byte
)
106 if (rds_waitread() >= 0) {
107 rds_rawwrite_nowait(byte
);
113 static int rds_write(unsigned char cmd
)
115 unsigned char sendbuffer
[8];
118 if (byte2trans(cmd
, sendbuffer
, 8) != 0){
121 for (i
=0; i
<8; i
++) {
122 rds_rawwrite(sendbuffer
[i
]);
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)
138 return rds_waitread();
141 static int rds_read(unsigned char databuffer
[], int datasize
)
143 #define READSIZE (8*datasize)
147 if (datasize
< 1) /* nothing to read */
150 /* to be able to use rds_readcycle_nowait()
151 I have to waitread() here */
152 if (rds_waitread() < 0)
155 memset(databuffer
, 0, datasize
);
157 for (i
=0; i
< READSIZE
; i
++)
158 if((j
=rds_readcycle_nowait()) < 0) {
161 databuffer
[i
/8]|=(RDS_DATA(j
) << (7-(i
%8)));
167 static int rds_ack(void)
169 int i
=rds_readcycle();
173 if (i
& RDS_DATAMASK
) {
176 printk(KERN_DEBUG
"aci-rds: NACK\n");
181 int aci_rds_cmd(unsigned char cmd
, unsigned char databuffer
[], int datasize
)
185 if (mutex_lock_interruptible(&aci_rds_mutex
))
190 /* RDS_RESET doesn't need further processing */
191 if (cmd
!=RDS_RESET
&& (rds_ack() || rds_read(databuffer
, datasize
)))
196 mutex_unlock(&aci_rds_mutex
);
200 EXPORT_SYMBOL(aci_rds_cmd
);
202 int __init
attach_aci_rds(void)
204 mutex_init(&aci_rds_mutex
);
208 void __exit
unload_aci_rds(void)
211 MODULE_LICENSE("GPL");