Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / media / radio / miropcm20-rds-core.c
bloba917a90cb5dc8cd3a4154621605b7404bb95f67b
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 <asm/semaphore.h>
22 #include <asm/io.h>
23 #include "../../../sound/oss/aci.h"
24 #include "miropcm20-rds-core.h"
26 #define DEBUG 0
28 static struct semaphore aci_rds_sem;
30 #define RDS_DATASHIFT 2 /* Bit 2 */
31 #define RDS_DATAMASK (1 << RDS_DATASHIFT)
32 #define RDS_BUSYMASK 0x10 /* Bit 4 */
33 #define RDS_CLOCKMASK 0x08 /* Bit 3 */
35 #define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
38 #if DEBUG
39 static void print_matrix(char array[], unsigned int length)
41 int i, j;
43 for (i=0; i<length; i++) {
44 printk(KERN_DEBUG "aci-rds: ");
45 for (j=7; j>=0; j--) {
46 printk("%d", (array[i] >> j) & 0x1);
48 if (i%8 == 0)
49 printk(" byte-border\n");
50 else
51 printk("\n");
54 #endif /* DEBUG */
56 static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
58 int i;
60 if (size != 8)
61 return -1;
62 for (i = 7; i >= 0; i--)
63 sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
64 sendbuffer[0] |= RDS_CLOCKMASK;
66 return 0;
69 static int rds_waitread(void)
71 unsigned char byte;
72 int i=2000;
74 do {
75 byte=inb(RDS_REGISTER);
76 i--;
78 while ((byte & RDS_BUSYMASK) && i);
80 if (i) {
81 #if DEBUG
82 printk(KERN_DEBUG "rds_waitread()");
83 print_matrix(&byte, 1);
84 #endif
85 return (byte);
86 } else {
87 printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n");
88 return -1;
92 /* don't use any ..._nowait() function if you are not sure what you do... */
94 static inline void rds_rawwrite_nowait(unsigned char byte)
96 #if DEBUG
97 printk(KERN_DEBUG "rds_rawwrite()");
98 print_matrix(&byte, 1);
99 #endif
100 outb(byte, RDS_REGISTER);
103 static int rds_rawwrite(unsigned char byte)
105 if (rds_waitread() >= 0) {
106 rds_rawwrite_nowait(byte);
107 return 0;
108 } else
109 return -1;
112 static int rds_write(unsigned char cmd)
114 unsigned char sendbuffer[8];
115 int i;
117 if (byte2trans(cmd, sendbuffer, 8) != 0){
118 return -1;
119 } else {
120 for (i=0; i<8; i++) {
121 rds_rawwrite(sendbuffer[i]);
124 return 0;
127 static int rds_readcycle_nowait(void)
129 rds_rawwrite_nowait(0);
130 return rds_waitread();
133 static int rds_readcycle(void)
135 if (rds_rawwrite(0) < 0)
136 return -1;
137 return rds_waitread();
140 static int rds_read(unsigned char databuffer[], int datasize)
142 #define READSIZE (8*datasize)
144 int i,j;
146 if (datasize < 1) /* nothing to read */
147 return 0;
149 /* to be able to use rds_readcycle_nowait()
150 I have to waitread() here */
151 if (rds_waitread() < 0)
152 return -1;
154 memset(databuffer, 0, datasize);
156 for (i=0; i< READSIZE; i++)
157 if((j=rds_readcycle_nowait()) < 0) {
158 return -1;
159 } else {
160 databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8)));
163 return 0;
166 static int rds_ack(void)
168 int i=rds_readcycle();
170 if (i < 0)
171 return -1;
172 if (i & RDS_DATAMASK) {
173 return 0; /* ACK */
174 } else {
175 printk(KERN_DEBUG "aci-rds: NACK\n");
176 return 1; /* NACK */
180 int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
182 int ret;
184 if (down_interruptible(&aci_rds_sem))
185 return -EINTR;
187 rds_write(cmd);
189 /* RDS_RESET doesn't need further processing */
190 if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
191 ret = -1;
192 else
193 ret = 0;
195 up(&aci_rds_sem);
197 return ret;
199 EXPORT_SYMBOL(aci_rds_cmd);
201 int __init attach_aci_rds(void)
203 init_MUTEX(&aci_rds_sem);
204 return 0;
207 void __exit unload_aci_rds(void)
210 MODULE_LICENSE("GPL");