miropcm20-rds-core.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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... [:
  9. *
  10. * Revision history:
  11. *
  12. * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de>
  13. * RDS support for MiroSound PCM20 radio
  14. */
  15. #include <linux/module.h>
  16. #include <linux/errno.h>
  17. #include <linux/string.h>
  18. #include <linux/init.h>
  19. #include <linux/slab.h>
  20. #include <linux/mutex.h>
  21. #include <asm/io.h>
  22. #include "../../../sound/oss/aci.h"
  23. #include "miropcm20-rds-core.h"
  24. #define DEBUG 0
  25. static struct mutex aci_rds_mutex;
  26. #define RDS_DATASHIFT 2 /* Bit 2 */
  27. #define RDS_DATAMASK (1 << RDS_DATASHIFT)
  28. #define RDS_BUSYMASK 0x10 /* Bit 4 */
  29. #define RDS_CLOCKMASK 0x08 /* Bit 3 */
  30. #define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
  31. #if DEBUG
  32. static void print_matrix(char array[], unsigned int length)
  33. {
  34. int i, j;
  35. for (i=0; i<length; i++) {
  36. printk(KERN_DEBUG "aci-rds: ");
  37. for (j=7; j>=0; j--) {
  38. printk("%d", (array[i] >> j) & 0x1);
  39. }
  40. if (i%8 == 0)
  41. printk(" byte-border\n");
  42. else
  43. printk("\n");
  44. }
  45. }
  46. #endif /* DEBUG */
  47. static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
  48. {
  49. int i;
  50. if (size != 8)
  51. return -1;
  52. for (i = 7; i >= 0; i--)
  53. sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
  54. sendbuffer[0] |= RDS_CLOCKMASK;
  55. return 0;
  56. }
  57. static int rds_waitread(void)
  58. {
  59. unsigned char byte;
  60. int i=2000;
  61. do {
  62. byte=inb(RDS_REGISTER);
  63. i--;
  64. }
  65. while ((byte & RDS_BUSYMASK) && i);
  66. if (i) {
  67. #if DEBUG
  68. printk(KERN_DEBUG "rds_waitread()");
  69. print_matrix(&byte, 1);
  70. #endif
  71. return (byte);
  72. } else {
  73. printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n");
  74. return -1;
  75. }
  76. }
  77. /* don't use any ..._nowait() function if you are not sure what you do... */
  78. static inline void rds_rawwrite_nowait(unsigned char byte)
  79. {
  80. #if DEBUG
  81. printk(KERN_DEBUG "rds_rawwrite()");
  82. print_matrix(&byte, 1);
  83. #endif
  84. outb(byte, RDS_REGISTER);
  85. }
  86. static int rds_rawwrite(unsigned char byte)
  87. {
  88. if (rds_waitread() >= 0) {
  89. rds_rawwrite_nowait(byte);
  90. return 0;
  91. } else
  92. return -1;
  93. }
  94. static int rds_write(unsigned char cmd)
  95. {
  96. unsigned char sendbuffer[8];
  97. int i;
  98. if (byte2trans(cmd, sendbuffer, 8) != 0){
  99. return -1;
  100. } else {
  101. for (i=0; i<8; i++) {
  102. rds_rawwrite(sendbuffer[i]);
  103. }
  104. }
  105. return 0;
  106. }
  107. static int rds_readcycle_nowait(void)
  108. {
  109. rds_rawwrite_nowait(0);
  110. return rds_waitread();
  111. }
  112. static int rds_readcycle(void)
  113. {
  114. if (rds_rawwrite(0) < 0)
  115. return -1;
  116. return rds_waitread();
  117. }
  118. static int rds_read(unsigned char databuffer[], int datasize)
  119. {
  120. #define READSIZE (8*datasize)
  121. int i,j;
  122. if (datasize < 1) /* nothing to read */
  123. return 0;
  124. /* to be able to use rds_readcycle_nowait()
  125. I have to waitread() here */
  126. if (rds_waitread() < 0)
  127. return -1;
  128. memset(databuffer, 0, datasize);
  129. for (i=0; i< READSIZE; i++)
  130. if((j=rds_readcycle_nowait()) < 0) {
  131. return -1;
  132. } else {
  133. databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8)));
  134. }
  135. return 0;
  136. }
  137. static int rds_ack(void)
  138. {
  139. int i=rds_readcycle();
  140. if (i < 0)
  141. return -1;
  142. if (i & RDS_DATAMASK) {
  143. return 0; /* ACK */
  144. } else {
  145. printk(KERN_DEBUG "aci-rds: NACK\n");
  146. return 1; /* NACK */
  147. }
  148. }
  149. int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
  150. {
  151. int ret;
  152. if (mutex_lock_interruptible(&aci_rds_mutex))
  153. return -EINTR;
  154. rds_write(cmd);
  155. /* RDS_RESET doesn't need further processing */
  156. if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
  157. ret = -1;
  158. else
  159. ret = 0;
  160. mutex_unlock(&aci_rds_mutex);
  161. return ret;
  162. }
  163. EXPORT_SYMBOL(aci_rds_cmd);
  164. int __init attach_aci_rds(void)
  165. {
  166. mutex_init(&aci_rds_mutex);
  167. return 0;
  168. }
  169. void __exit unload_aci_rds(void)
  170. {
  171. }
  172. MODULE_LICENSE("GPL");