radio-trust.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:7k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* radio-trust.c - Trust FM Radio card driver for Linux 2.2 
  2.  * by Eric Lammerts <eric@scintilla.utwente.nl>
  3.  *
  4.  * Based on radio-aztech.c. Original notes:
  5.  *
  6.  * Adapted to support the Video for Linux API by 
  7.  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
  8.  *
  9.  * Quay Ly
  10.  * Donald Song
  11.  * Jason Lewis      (jlewis@twilight.vtc.vsc.edu) 
  12.  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  13.  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  14.  *
  15.  * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
  16.  */
  17. #include <stdarg.h>
  18. #include <linux/module.h>
  19. #include <linux/init.h>
  20. #include <linux/ioport.h>
  21. #include <asm/io.h>
  22. #include <asm/uaccess.h>
  23. #include <linux/videodev.h>
  24. #include <linux/config.h> /* CONFIG_RADIO_TRUST_PORT  */
  25. /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
  26. #ifndef CONFIG_RADIO_TRUST_PORT
  27. #define CONFIG_RADIO_TRUST_PORT -1
  28. #endif
  29. static int io = CONFIG_RADIO_TRUST_PORT; 
  30. static int radio_nr = -1;
  31. static int ioval = 0xf;
  32. static int users = 0;
  33. static __u16 curvol;
  34. static __u16 curbass;
  35. static __u16 curtreble;
  36. static unsigned long curfreq;
  37. static int curstereo;
  38. static int curmute;
  39. /* i2c addresses */
  40. #define TDA7318_ADDR 0x88
  41. #define TSA6060T_ADDR 0xc4
  42. #define TR_DELAY do { inb(io); inb(io); inb(io); } while(0)
  43. #define TR_SET_SCL outb(ioval |= 2, io)
  44. #define TR_CLR_SCL outb(ioval &= 0xfd, io)
  45. #define TR_SET_SDA outb(ioval |= 1, io)
  46. #define TR_CLR_SDA outb(ioval &= 0xfe, io)
  47. static void write_i2c(int n, ...)
  48. {
  49. unsigned char val, mask;
  50. va_list args;
  51. va_start(args, n);
  52. /* start condition */
  53. TR_SET_SDA;
  54. TR_SET_SCL;
  55. TR_DELAY;
  56. TR_CLR_SDA;
  57. TR_CLR_SCL;
  58. TR_DELAY;
  59. for(; n; n--) {
  60. val = va_arg(args, unsigned);
  61. for(mask = 0x80; mask; mask >>= 1) {
  62. if(val & mask)
  63. TR_SET_SDA;
  64. else
  65. TR_CLR_SDA;
  66. TR_SET_SCL;
  67. TR_DELAY;
  68. TR_CLR_SCL;
  69. TR_DELAY;
  70. }
  71. /* acknowledge bit */
  72. TR_SET_SDA;
  73. TR_SET_SCL;
  74. TR_DELAY;
  75. TR_CLR_SCL;
  76. TR_DELAY;
  77. }
  78. /* stop condition */
  79. TR_CLR_SDA;
  80. TR_DELAY;
  81. TR_SET_SCL;
  82. TR_DELAY;
  83. TR_SET_SDA;
  84. TR_DELAY;
  85. va_end(args);
  86. }
  87. static void tr_setvol(__u16 vol)
  88. {
  89. curvol = vol / 2048;
  90. write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f);
  91. }
  92. static int basstreble2chip[15] = {
  93. 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
  94. };
  95. static void tr_setbass(__u16 bass)
  96. {
  97. curbass = bass / 4370;
  98. write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]);
  99. }
  100. static void tr_settreble(__u16 treble)
  101. {
  102. curtreble = treble / 4370;
  103. write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]);
  104. }
  105. static void tr_setstereo(int stereo)
  106. {
  107. curstereo = !!stereo;
  108. ioval = (ioval & 0xfb) | (!curstereo << 2);
  109. outb(ioval, io);
  110. }
  111. static void tr_setmute(int mute)
  112. {
  113. curmute = !!mute;
  114. ioval = (ioval & 0xf7) | (curmute << 3);
  115. outb(ioval, io);
  116. }
  117. static int tr_getsigstr(void)
  118. {
  119. int i, v;
  120. for(i = 0, v = 0; i < 100; i++) v |= inb(io);
  121. return (v & 1)? 0 : 0xffff;
  122. }
  123. static int tr_getstereo(void)
  124. {
  125. /* don't know how to determine it, just return the setting */
  126. return curstereo;
  127. }
  128. static void tr_setfreq(unsigned long f)
  129. {
  130. f /= 160; /* Convert to 10 kHz units */
  131. f += 1070; /* Add 10.7 MHz IF */
  132. write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
  133. }
  134. static int tr_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
  135. {
  136. switch(cmd)
  137. {
  138. case VIDIOCGCAP:
  139. {
  140. struct video_capability v;
  141. v.type=VID_TYPE_TUNER;
  142. v.channels=1;
  143. v.audios=1;
  144. /* No we don't do pictures */
  145. v.maxwidth=0;
  146. v.maxheight=0;
  147. v.minwidth=0;
  148. v.minheight=0;
  149. strcpy(v.name, "Trust FM Radio");
  150. if(copy_to_user(arg,&v,sizeof(v)))
  151. return -EFAULT;
  152. return 0;
  153. }
  154. case VIDIOCGTUNER:
  155. {
  156. struct video_tuner v;
  157. if(copy_from_user(&v, arg,sizeof(v))!=0) 
  158. return -EFAULT;
  159. if(v.tuner) /* Only 1 tuner */ 
  160. return -EINVAL;
  161. v.rangelow = 87500 * 16;
  162. v.rangehigh = 108000 * 16;
  163. v.flags = VIDEO_TUNER_LOW;
  164. v.mode = VIDEO_MODE_AUTO;
  165. v.signal = tr_getsigstr();
  166. if(tr_getstereo())
  167. v.flags |= VIDEO_TUNER_STEREO_ON;
  168. strcpy(v.name, "FM");
  169. if(copy_to_user(arg,&v, sizeof(v)))
  170. return -EFAULT;
  171. return 0;
  172. }
  173. case VIDIOCSTUNER:
  174. {
  175. struct video_tuner v;
  176. if(copy_from_user(&v, arg, sizeof(v)))
  177. return -EFAULT;
  178. if(v.tuner != 0)
  179. return -EINVAL;
  180. return 0;
  181. }
  182. case VIDIOCGFREQ:
  183. if(copy_to_user(arg, &curfreq, sizeof(curfreq)))
  184. return -EFAULT;
  185. return 0;
  186. case VIDIOCSFREQ:
  187. {
  188. unsigned long f;
  189. if(copy_from_user(&f, arg, sizeof(curfreq)))
  190. return -EFAULT;
  191. tr_setfreq(f);
  192. return 0;
  193. }
  194. case VIDIOCGAUDIO:
  195. {
  196. struct video_audio v;
  197. memset(&v,0, sizeof(v));
  198. v.flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
  199.           VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
  200. v.mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
  201. v.volume = curvol * 2048;
  202. v.step = 2048;
  203. v.bass = curbass * 4370;
  204. v.treble = curtreble * 4370;
  205. strcpy(v.name, "Trust FM Radio");
  206. if(copy_to_user(arg,&v, sizeof(v)))
  207. return -EFAULT;
  208. return 0;
  209. }
  210. case VIDIOCSAUDIO:
  211. {
  212. struct video_audio v;
  213. if(copy_from_user(&v, arg, sizeof(v))) 
  214. return -EFAULT;
  215. if(v.audio) 
  216. return -EINVAL;
  217. tr_setvol(v.volume);
  218. tr_setbass(v.bass);
  219. tr_settreble(v.treble);
  220. tr_setstereo(v.mode & VIDEO_SOUND_STEREO);
  221. tr_setmute(v.flags & VIDEO_AUDIO_MUTE);
  222. return 0;
  223. }
  224. default:
  225. return -ENOIOCTLCMD;
  226. }
  227. }
  228. static int tr_open(struct video_device *dev, int flags)
  229. {
  230. if(users)
  231. return -EBUSY;
  232. users++;
  233. return 0;
  234. }
  235. static void tr_close(struct video_device *dev)
  236. {
  237. users--;
  238. }
  239. static struct video_device trust_radio=
  240. {
  241. owner: THIS_MODULE,
  242. name: "Trust FM Radio",
  243. type: VID_TYPE_TUNER,
  244. hardware: VID_HARDWARE_TRUST,
  245. open: tr_open,
  246. close: tr_close,
  247. ioctl: tr_ioctl,
  248. };
  249. static int __init trust_init(void)
  250. {
  251. if(io == -1) {
  252. printk(KERN_ERR "You must set an I/O address with io=0x???n");
  253. return -EINVAL;
  254. }
  255. if(!request_region(io, 2, "Trust FM Radio")) {
  256. printk(KERN_ERR "trust: port 0x%x already in usen", io);
  257. return -EBUSY;
  258. }
  259. if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1)
  260. {
  261. release_region(io, 2);
  262. return -EINVAL;
  263. }
  264. printk(KERN_INFO "Trust FM Radio card driver v1.0.n");
  265. write_i2c(2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
  266. write_i2c(2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
  267. write_i2c(2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
  268. write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
  269. write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
  270. tr_setvol(0x8000);
  271. tr_setbass(0x8000);
  272. tr_settreble(0x8000);
  273. tr_setstereo(1);
  274. /* mute card - prevents noisy bootups */
  275. tr_setmute(1);
  276. return 0;
  277. }
  278. MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
  279. MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
  280. MODULE_LICENSE("GPL");
  281. MODULE_PARM(io, "i");
  282. MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
  283. MODULE_PARM(radio_nr, "i");
  284. EXPORT_NO_SYMBOLS;
  285. static void __exit cleanup_trust_module(void)
  286. {
  287. video_unregister_device(&trust_radio);
  288. release_region(io, 2);
  289. }
  290. module_init(trust_init);
  291. module_exit(cleanup_trust_module);