radio-si4703.c
上传用户:ledjyj
上传日期:2014-08-27
资源大小:2639k
文件大小:14k
源码类别:

驱动编程

开发平台:

Unix_Linux

  1. /* SI4703 Radio Card driver for radio support
  2.  * (c) 1999 Dr. Henrik Seidel <Henrik.Seidel@gmx.de>
  3.  *
  4.  * Card manufacturer:
  5.  * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e
  6.  *
  7.  * Notes on the hardware
  8.  *
  9.  * This card has two output sockets, one for speakers and one for line.
  10.  * The speaker output has volume control, but only in four discrete
  11.  * steps. The line output has neither volume control nor mute.
  12.  *
  13.  * The card has auto-stereo according to its manual, although it all
  14.  * sounds mono to me (even with the Win/DOS drivers). Maybe it's my
  15.  * antenna - I really don't know for sure.
  16.  *
  17.  * Frequency control is done digitally.
  18.  *
  19.  * Volume control is done digitally, but there are only four different
  20.  * possible values. So you should better always turn the volume up and
  21.  * use line control. I got the best results by connecting line output
  22.  * to the sound card microphone input. For such a configuration the
  23.  * volume control has no effect, since volume control only influences
  24.  * the speaker output.
  25.  *
  26.  * There is no explicit mute/unmute. So I set the radio frequency to a
  27.  * value where I do expect just noise and turn the speaker volume down.
  28.  * The frequency change is necessary since the card never seems to be
  29.  * completely silent.
  30.  */
  31. #include <linux/module.h> /* Modules                        */
  32. #include <linux/init.h> /* Initdata                       */
  33. #include <linux/ioport.h> /* request_region   */
  34. #include <linux/proc_fs.h> /* radio card status report   */
  35. #include <asm/io.h> /* outb, outb_p                   */
  36. #include <asm/uaccess.h> /* copy to/from user              */
  37. #include <linux/videodev.h> /* kernel radio structs           */
  38. #include <linux/config.h> /* CONFIG_RADIO_SI4703_*         */
  39. #include <linux/types.h>
  40. #include <linux/interrupt.h>
  41. #include <linux/workqueue.h>
  42. #include "SI4703API.h"
  43. #define BANNER "SI4703 Radio Card driver v0.1n"
  44. #ifndef CONFIG_RADIO_SI4703_MUTEFREQ
  45. #define CONFIG_RADIO_SI4703_MUTEFREQ 0
  46. #endif
  47. #ifndef CONFIG_PROC_FS
  48. #undef CONFIG_RADIO_SI4703_PROC_FS
  49. #endif
  50. #ifndef TRUE
  51. #define TRUE 1
  52. #endif
  53. #ifndef FALSE
  54. #define FALSE 0
  55. #endif
  56. struct SI4703_device {
  57. int users;
  58. int curvol;
  59. int muted;
  60. unsigned long curfreq;
  61. unsigned long mutefreq;
  62. struct mutex lock;
  63.     __u32 audmode;
  64.     struct RDS_DATA irq_data;
  65. spinlock_t irq_lock;
  66. wait_queue_head_t irq_queue;
  67.     struct workqueue_struct *radio_irq_workq;
  68. struct work_struct fm_event_work;
  69. struct fasync_struct *async_queue;
  70. };
  71. static struct SI4703_device SI4703_unit =
  72. {
  73. .curfreq = CONFIG_RADIO_SI4703_MUTEFREQ,
  74. .mutefreq = CONFIG_RADIO_SI4703_MUTEFREQ,
  75. };
  76. static int SI4703_ioctl(struct inode *inode, struct file *file,
  77.  unsigned int cmd, unsigned long arg);
  78. static int SI4703_Read(struct file *file, char __user *arg, size_t count, loff_t *offset);
  79. #ifdef CONFIG_RADIO_SI4703_PROC_FS
  80. static int SI4703_get_info(char *buf, char **start, off_t offset, int len);
  81. #endif
  82. static void query_radio_ctrl(struct v4l2_queryctrl *param);
  83. static void get_radio_ctrl(struct v4l2_control *param);
  84. static void set_radio_ctrl(struct v4l2_control *param);
  85. static int  SI4703_init_irq(void);
  86. static int SI4703_do_ioctl(struct inode *inode, struct file *file,
  87.     unsigned int cmd, void *arg)
  88. {
  89. struct video_device *dev = video_devdata(file);
  90. struct SI4703_device *SI4703 = dev->priv;
  91. switch (cmd) {
  92. case VIDIOC_QUERYCAP:
  93. {
  94. struct v4l2_capability *v = arg;
  95. memset(v,0,sizeof(*v));
  96. v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
  97. strcpy(v->driver, "SI4703");
  98. return 0;
  99. }
  100.     case VIDIOC_RADIO_ON:
  101. {
  102.             printk(KERN_ERR "radio-SI4703: ioctl radio onn");
  103.             FM_SI47XX_PowerUp();
  104. return 0;
  105. }
  106. case VIDIOC_RADIO_OFF:
  107. {
  108.             printk(KERN_ERR "radio-SI4703: ioctl radio offn");
  109.             FM_SI47XX_PowerDown();
  110. return 0;
  111. }
  112. case VIDIOC_G_TUNER:
  113. {
  114. struct v4l2_tuner *v = arg;
  115. // if (v->tuner) /* Only 1 tuner */
  116. // return -EINVAL;
  117.           printk(KERN_ERR "radio-SI4703: ioctl get tunern");
  118. v->rangelow = 8750;
  119. v->rangehigh = 10800;
  120. v->type = V4L2_TUNER_RADIO;
  121. v->capability = V4L2_TUNER_CAP_STEREO;
  122. v->signal = FM_SI47XX_ReadRSSI(); /*  get the signal strength */
  123. strcpy(v->name, "SI4703");
  124. return 0;
  125. }
  126. case VIDIOC_S_TUNER:
  127. {
  128. struct v4l2_tuner *v = arg;
  129. // if (v->tuner != 0)
  130. // return -EINVAL;
  131. /* Only 1 tuner so no setting needed ! */
  132.             printk(KERN_ERR "radio-SI4703: ioctl set tunern");
  133.            SI4703->audmode = v->audmode;
  134. return 0;
  135. }
  136. case VIDIOC_G_FREQUENCY:
  137. {
  138. struct v4l2_frequency *freq = arg;
  139.         printk(KERN_ERR "radio-SI4703: ioctl get freqn");
  140. freq->frequency = SI4703->curfreq;
  141.         freq->type = V4L2_TUNER_RADIO;
  142. return 0;
  143. }
  144. case VIDIOC_S_FREQUENCY:
  145. {
  146. struct v4l2_frequency *freq = arg;
  147.          printk(KERN_ERR "radio-SI4703: ioctl set freqn");
  148. SI4703->curfreq = freq->frequency;
  149. FM_SI47XX_Tune(SI4703->curfreq);
  150. return 0;
  151. }
  152.     case VIDIOC_QUERYCTRL:
  153.     {
  154.         struct v4l2_queryctrl *v = arg;
  155.         query_radio_ctrl(v);
  156.         return 0;
  157.     }
  158.     case VIDIOC_G_CTRL:
  159.     {
  160.         struct v4l2_control * v = arg;
  161.         get_radio_ctrl(v);
  162.         return 0;
  163.     }
  164.     case VIDIOC_S_CTRL:
  165.     {
  166.         struct v4l2_control * v = arg;
  167.           printk(KERN_ERR "radio-SI4703: ioctl set ctrln");
  168.         set_radio_ctrl(v);
  169.         return 0;
  170.     }
  171.     case RADIO_SCAN_NEXT:
  172.     {
  173.         struct radio_scan *v = arg;
  174.         if(SEEKUP == v->direction) {
  175.            printk(KERN_ERR "radio-SI4703: ioctl seek upn");
  176.             FM_SI47XX_Seek(SEEKUP,&v->channel, &v->scanok);
  177.         }
  178.         if(SEEKDOWN == v->direction) {
  179.             printk(KERN_ERR "radio-SI4703: ioctl seek downn");
  180.             FM_SI47XX_Seek(SEEKDOWN, &v->channel,&v->scanok);
  181.         }
  182.        return 0;
  183.     }
  184.         
  185. default:
  186. return -ENOIOCTLCMD;
  187. }
  188. }
  189. static void query_radio_ctrl(struct v4l2_queryctrl *param)
  190. {
  191.    struct  v4l2_queryctrl *v = param;
  192.     switch (v->id) {
  193.     case V4L2_CID_AUDIO_VOLUME:
  194.     {
  195.         v->type = V4L2_CTRL_TYPE_INTEGER;
  196.         v->minimum = 0;
  197.         v->maximum = 100;
  198.         v->step =20;
  199.         return;
  200.     }
  201.     case V4L2_CID_AUDIO_MUTE:
  202.     {
  203.        v->type = V4L2_CTRL_TYPE_BOOLEAN;
  204.        return;
  205.     }
  206.     default:
  207.     {
  208.         v->flags = V4L2_CTRL_FLAG_DISABLED;
  209.         return;
  210.     }
  211.     }
  212. }
  213. static void get_radio_ctrl(struct v4l2_control *param)
  214. {
  215.    struct v4l2_control *v = param;
  216.     switch (v->id) {
  217.     case V4L2_CID_AUDIO_VOLUME:
  218.     {
  219.         v->value = SI4703_unit.curvol;
  220.         return;
  221.    
  222.     }
  223.     case V4L2_CID_AUDIO_MUTE:
  224.     {
  225.        v->value = SI4703_unit.muted ;
  226.        return;
  227.     }
  228.     default:
  229.     {
  230.         v->value = -1;
  231.         return;
  232.     }
  233.     }
  234. }
  235. static void set_radio_ctrl(struct v4l2_control *param)
  236. {
  237.     struct v4l2_control *v = param;
  238.     switch (v->id) {
  239.     case V4L2_CID_AUDIO_VOLUME:
  240.     {
  241.      FM_SI47XX_Volume(v->value);
  242.      SI4703_unit.curvol = v->value;
  243.      return;
  244.     }
  245.     case V4L2_CID_AUDIO_MUTE:
  246.     {
  247.         if (1 == v->value) {
  248.             FM_SI47XX_MuteVolume();
  249.             SI4703_unit.muted =1;
  250.         }
  251.         else {
  252.             FM_SI47XX_DMuteVolume();
  253.             SI4703_unit.muted =0;
  254.         }
  255.             
  256.       return;
  257.     }
  258.     default:
  259.     {
  260.         printk(KERN_ERR "radio-SI4703: error controln");
  261.         return;
  262.     }
  263.        
  264.     }
  265. }
  266. static int SI4703_ioctl(struct inode *inode, struct file *file,
  267.  unsigned int cmd, unsigned long arg)
  268. {
  269.     printk(KERN_ERR "radio-SI4703: enter ioctln");
  270.     return video_usercopy(inode, file, cmd, arg, SI4703_do_ioctl);
  271. }
  272. static irqreturn_t si4703_radio_interrupt(int irq, void *dev_id,
  273. struct pt_regs *regs)
  274. {
  275.      struct SI4703_device *radio = &SI4703_unit;
  276.     printk(KERN_ERR "radio-SI4703: interruptn");
  277.    //spin_lock(&radio->irq_lock);
  278. // radio->irq_data.RDSA = ReadRDS_BLOCK(RDSA);
  279.    // radio->irq_data.RDSB = ReadRDS_BLOCK(RDSB);
  280.    // radio->irq_data.RDSC = ReadRDS_BLOCK(RDSC);
  281.   //  radio->irq_data.RDSD= ReadRDS_BLOCK(RDSD);
  282.    // radio->irq_data.RDSA = 100;
  283. //spin_unlock(&radio->irq_lock);
  284.     disable_irq(IRQ_GPIO(113));
  285. queue_work(radio->radio_irq_workq, &radio->fm_event_work);
  286. return IRQ_HANDLED;
  287. }
  288. static int SI4703_Read(struct file *file, char __user *arg, size_t count, loff_t *offset)
  289. {
  290.     struct SI4703_device *radio = &SI4703_unit;
  291.     DECLARE_WAITQUEUE(wait, current);
  292. struct RDS_DATA data;
  293. ssize_t ret;
  294. //if (count != sizeof(unsigned int) && count < sizeof(unsigned long))
  295. //return -EINVAL;
  296. add_wait_queue(&radio->irq_queue, &wait);
  297. do {
  298. __set_current_state(TASK_INTERRUPTIBLE);
  299. spin_lock_irq(&radio->irq_lock);
  300. data = radio->irq_data;
  301. radio->irq_data.RDSA = 0;
  302. spin_unlock_irq(&radio->irq_lock);
  303. if (data.RDSA != 0) {
  304. ret = 0;
  305. break;
  306. }
  307. if (file->f_flags & O_NONBLOCK) {
  308. ret = -EAGAIN;
  309. break;
  310. }
  311. if (signal_pending(current)) {
  312. ret = -ERESTARTSYS;
  313. break;
  314. }
  315. schedule();
  316. } while (1);
  317. set_current_state(TASK_RUNNING);
  318. remove_wait_queue(&radio->irq_queue, &wait);
  319. /*if (ret == 0) {
  320. if (radio->read_callback)
  321. data = radio->read_callback(rtc->class_dev.dev,
  322.        data);}*/
  323.          
  324.     return  copy_to_user(arg,&data,sizeof(data))? -EFAULT : sizeof(data);
  325.  }
  326. static unsigned int SI4703_dev_poll(struct file *file, poll_table *wait)
  327. {
  328.  struct SI4703_device *radio = &SI4703_unit;
  329.  struct RDS_DATA data;
  330. poll_wait(file, &radio->irq_queue, wait);
  331. data = radio->irq_data;
  332. return (data.RDSA != 0) ? (POLLIN | POLLRDNORM) : 0;
  333. }
  334. static int SI4703_dev_fasync(int fd, struct file *file, int on)
  335. {
  336. struct SI4703_device *radio = &SI4703_unit;
  337. return fasync_helper(fd, file, on, &radio->async_queue);
  338. }
  339. static void radio_fm_irq_worker(void *ptr) 
  340. {
  341. //spin_lock(&radio->irq_lock);
  342.     struct SI4703_device *radio = ptr;
  343. radio->irq_data.RDSA = ReadRDS_BLOCK(RDSA);
  344.     radio->irq_data.RDSB = ReadRDS_BLOCK(RDSB);
  345.     radio->irq_data.RDSC = ReadRDS_BLOCK(RDSC);
  346.     radio->irq_data.RDSD= ReadRDS_BLOCK(RDSD);
  347.     radio->irq_data.RDSA = 100;
  348.     wake_up_interruptible(&radio->irq_queue);
  349. kill_fasync(&radio->async_queue, SIGIO, POLL_IN);
  350.     enable_irq(IRQ_GPIO(113));
  351. //spin_unlock(&radio->irq_lock);
  352. }
  353. static int SI4703_init_irq(void)
  354. {
  355.     struct SI4703_device *radio = &SI4703_unit;
  356.    INIT_WORK(&radio->fm_event_work, radio_fm_irq_worker, radio);
  357. if ((radio->radio_irq_workq = 
  358. create_singlethread_workqueue("si4703radio")) == NULL) {
  359. printk(KERN_ERR"could not create radio irq work queuen"); 
  360. return -EINVAL; 
  361. }
  362.     if(request_irq (IRQ_GPIO(113), si4703_radio_interrupt, SA_INTERRUPT, "si4703_radio", NULL))
  363.     {
  364.         printk(KERN_ERR "radio-SI4703: error request irqn");
  365.         destroy_workqueue(radio->radio_irq_workq);
  366.         free_irq(IRQ_GPIO(113),NULL);
  367.         return -EINVAL; 
  368.     }
  369. return 0; 
  370. }
  371. static struct file_operations SI4703_fops = {
  372. .owner = THIS_MODULE,
  373. .open           = video_exclusive_open,
  374.     .read           = SI4703_Read,
  375. .release        = video_exclusive_release,
  376. .ioctl = SI4703_ioctl,
  377.     .poll       = SI4703_dev_poll,
  378.     .fasync = SI4703_dev_fasync,
  379. .compat_ioctl = v4l_compat_ioctl32,
  380. .llseek         = no_llseek,
  381. };
  382. static struct video_device SI4703_radio =
  383. {
  384. .owner = THIS_MODULE,
  385. .name = "SI4703 Radio",
  386. .type = VID_TYPE_TUNER,
  387. .hardware = VID_HARDWARE_SI4703,
  388. .fops           = &SI4703_fops,
  389. };
  390. #ifdef CONFIG_RADIO_SI4703_PROC_FS
  391. static int SI4703_get_info(char *buf, char **start, off_t offset, int len)
  392. {
  393. char *out = buf;
  394. #ifdef MODULE
  395.     #define MODULEPROCSTRING "Driver loaded as a module"
  396. #else
  397.     #define MODULEPROCSTRING "Driver compiled into kernel"
  398. #endif
  399. /* output must be kept under PAGE_SIZE */
  400. out += sprintf(out, BANNER);
  401. out += sprintf(out, "Load type: " MODULEPROCSTRING "nn");
  402. out += sprintf(out, "frequency = %lu kHzn",
  403. SI4703_unit.curfreq >> 4);
  404. out += sprintf(out, "volume = %dn", SI4703_unit.curvol);
  405. out += sprintf(out, "mute = %sn", SI4703_unit.muted ?
  406. "on" : "off");
  407. out += sprintf(out, "mute frequency = %lu kHzn",
  408. SI4703_unit.mutefreq >> 4);
  409. return out - buf;
  410. }
  411. #endif /* CONFIG_RADIO_SI4703_PROC_FS */
  412. MODULE_AUTHOR("Beck He");
  413. MODULE_DESCRIPTION("A driver for the SI4703 radio card .");
  414. MODULE_LICENSE("GPL");
  415. static int radio_nr = -1;
  416. module_param(radio_nr, int, 0);
  417. #ifdef MODULE
  418. static unsigned long mutefreq = 0;
  419. module_param(mutefreq, ulong, 0);
  420. MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
  421. #endif
  422. static int __init SI4703_init(void)
  423. {
  424.      struct SI4703_device *radio = &SI4703_unit;
  425. #ifdef MODULE
  426. if (mutefreq < 87000 || mutefreq > 108500) {
  427. printk(KERN_ERR "radio-SI4703: You must set a frequency (in kHz) used when muting the card,n");
  428. printk(KERN_ERR "radio-SI4703: e.g. with "mutefreq=87500" (87000 <= mutefreq <= 108500)n");
  429. return -EINVAL;
  430. }
  431. SI4703_unit.mutefreq = mutefreq;
  432. #endif /* MODULE */
  433. printk(KERN_INFO BANNER);
  434. mutex_init(&radio->lock);
  435.     spin_lock_init(&radio->irq_lock);
  436.     init_waitqueue_head(&radio->irq_queue);
  437. SI4703_radio.priv = &SI4703_unit;
  438. if (video_register_device(&SI4703_radio, VFL_TYPE_RADIO, radio_nr) == -1)
  439. {
  440. return -EINVAL;
  441. }
  442.     FM_SI47XX_Init();
  443.     SI4703_init_irq();
  444. //printk(KERN_INFO "radio-SI4703: mute frequency is %lu kHz.n",
  445. //       SI4703_unit.mutefreq);
  446. //SI4703_unit.mutefreq <<= 4;
  447. /* mute card - prevents noisy bootups */
  448. // SI4703_mute(&SI4703_unit);
  449. #ifdef CONFIG_RADIO_SI4703_PROC_FS
  450. if (!create_proc_info_entry("driver/radio-SI4703", 0, NULL,
  451.     SI4703_get_info)) 
  452.      printk(KERN_ERR "radio-SI4703: registering /proc/driver/radio-SI4703 failedn");
  453. #endif
  454. return 0;
  455. }
  456. static void __exit SI4703_cleanup_module(void)
  457. {
  458. #ifdef CONFIG_RADIO_SI4703_PROC_FS
  459. remove_proc_entry("driver/radio-SI4703", NULL);
  460. #endif
  461.     free_irq(IRQ_GPIO(113),NULL);
  462. video_unregister_device(&SI4703_radio);
  463. }
  464. module_init(SI4703_init);
  465. module_exit(SI4703_cleanup_module);