radio-gemtek-pci.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  ***************************************************************************
  3.  *     
  4.  *     radio-gemtek-pci.c - Gemtek PCI Radio driver
  5.  *     (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
  6.  *
  7.  ***************************************************************************
  8.  *
  9.  *     This program is free software; you can redistribute it and/or
  10.  *     modify it under the terms of the GNU General Public License as
  11.  *     published by the Free Software Foundation; either version 2 of
  12.  *     the License, or (at your option) any later version.
  13.  *
  14.  *     This program is distributed in the hope that it will be useful,
  15.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *     GNU General Public License for more details.
  18.  *
  19.  *     You should have received a copy of the GNU General Public
  20.  *     License along with this program; if not, write to the Free
  21.  *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
  22.  *     USA.
  23.  *
  24.  ***************************************************************************
  25.  *
  26.  *     Gemtek Corp still silently refuses to release any specifications
  27.  *     of their multimedia devices, so the protocol still has to be
  28.  *     reverse engineered.
  29.  *
  30.  *     The v4l code was inspired by Jonas Munsin's  Gemtek serial line
  31.  *     radio device driver.
  32.  *
  33.  *     Please, let me know if this piece of code was useful :)
  34.  * 
  35.  *     TODO: multiple device support and portability were not tested
  36.  *
  37.  ***************************************************************************
  38.  */
  39. #include <linux/version.h>
  40. #include <linux/config.h>
  41. #include <linux/types.h>
  42. #include <linux/list.h>
  43. #include <linux/module.h>
  44. #include <linux/init.h>
  45. #include <linux/pci.h>
  46. #include <linux/videodev.h>
  47. #include <linux/errno.h>
  48. #include <asm/io.h>
  49. #include <asm/uaccess.h>
  50. #ifndef PCI_VENDOR_ID_GEMTEK
  51. #define PCI_VENDOR_ID_GEMTEK 0x5046
  52. #endif
  53. #ifndef PCI_DEVICE_ID_GEMTEK_PR103
  54. #define PCI_DEVICE_ID_GEMTEK_PR103 0x1001
  55. #endif
  56. #ifndef GEMTEK_PCI_RANGE_LOW
  57. #define GEMTEK_PCI_RANGE_LOW (87*16000)
  58. #endif
  59. #ifndef GEMTEK_PCI_RANGE_HIGH
  60. #define GEMTEK_PCI_RANGE_HIGH (108*16000)
  61. #endif
  62. #ifndef TRUE
  63. #define TRUE (1)
  64. #endif
  65. #ifndef FALSE 
  66. #define FALSE (0)
  67. #endif
  68. struct gemtek_pci_card {
  69. struct video_device *videodev;
  70. u32 iobase;
  71. u32 length;
  72. u8  chiprev;
  73. u16 model;
  74. u32 current_frequency;
  75. u8  mute;
  76. };
  77. static const char rcsid[] = "$Id: radio-gemtek-pci.c,v 1.1 2001/07/23 08:08:16 ted Exp ted $";
  78. static int nr_radio = -1;
  79. static int gemtek_pci_open( struct video_device *dev, int flags)
  80. {
  81. struct gemtek_pci_card *card =  dev->priv;
  82. /* Paranoid check */
  83. if ( !card )
  84. return -ENODEV;
  85. return 0;
  86. }
  87. static void gemtek_pci_close( struct video_device *dev )
  88. {
  89. /*
  90.  *  The module usage is managed by 'videodev'
  91.  */
  92. }
  93. static inline u8 gemtek_pci_out( u16 value, u32 port )
  94. {
  95. outw( value, port );
  96. return (u8)value;
  97. }
  98. #define _b0( v ) *((u8 *)&v)  
  99. static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
  100. {
  101. register u8 byte = *last_byte;
  102. if ( !value ) {
  103. if ( !keep )
  104. value = (u16)port;
  105. byte &= 0xfd;
  106. } else
  107. byte |= 2;
  108. _b0( value ) = byte;
  109. outw( value, port );
  110. byte |= 1;
  111. _b0( value ) = byte;
  112. outw( value, port );
  113. byte &= 0xfe;
  114. _b0( value ) = byte;
  115. outw( value, port );
  116. *last_byte = byte;
  117. }
  118. static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
  119. {
  120. __gemtek_pci_cmd( 0x00, port, last_byte, FALSE );
  121. }
  122. static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
  123. {
  124. __gemtek_pci_cmd( cmd, port, last_byte, TRUE );
  125. }
  126. static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
  127. {
  128. register int i;
  129. register u32 value = frequency / 200 + 856;
  130. register u16 mask = 0x8000;
  131. u8 last_byte;
  132. u32 port = card->iobase;
  133. last_byte = gemtek_pci_out( 0x06, port );
  134. i = 0;
  135. do {
  136. gemtek_pci_nil( port, &last_byte );
  137. i++;
  138. } while ( i < 9 );
  139. i = 0;
  140. do {
  141. gemtek_pci_cmd( value & mask, port, &last_byte );
  142. mask >>= 1;
  143. i++;
  144. } while ( i < 16 );
  145. outw( 0x10, port );
  146. }
  147. static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
  148. {
  149. outb( 0x1f, card->iobase );
  150. card->mute = TRUE;
  151. }
  152. static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
  153. {
  154. if ( card->mute ) {
  155. gemtek_pci_setfrequency( card, card->current_frequency );
  156. card->mute = FALSE;
  157. }
  158. }
  159. static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card )
  160. {
  161. return ( inb( card->iobase ) & 0x08 ) ? 0 : 1;
  162. }
  163. static int gemtek_pci_ioctl( struct video_device *dev, unsigned int cmd, void *arg)
  164. {
  165. struct gemtek_pci_card *card = dev->priv;
  166. switch ( cmd ) {
  167. case VIDIOCGCAP:
  168. {
  169. struct video_capability c;
  170. c.type = VID_TYPE_TUNER;
  171. c.channels = 1;
  172. c.audios = 1;
  173. c.maxwidth = 0;
  174. c.maxheight = 0;
  175. c.minwidth = 0;
  176. c.minheight = 0;
  177. strcpy( c.name, "Gemtek PCI Radio" );
  178. if ( copy_to_user( arg, &c, sizeof( c ) ) )
  179. return -EFAULT;
  180. return 0;
  181. case VIDIOCGTUNER:
  182. {
  183. struct video_tuner t;
  184. int signal;
  185. if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) )
  186. return -EFAULT;
  187. if ( t.tuner ) 
  188. return -EINVAL;
  189. signal = gemtek_pci_getsignal( card );
  190. t.rangelow = GEMTEK_PCI_RANGE_LOW;
  191. t.rangehigh = GEMTEK_PCI_RANGE_HIGH;
  192. t.flags = VIDEO_TUNER_LOW | (7 << signal) ;
  193. t.mode = VIDEO_MODE_AUTO;
  194. t.signal = 0xFFFF * signal;
  195. strcpy( t.name, "FM" );
  196. if ( copy_to_user( arg, &t, sizeof( struct video_tuner ) ) )
  197. return -EFAULT;
  198. return 0;
  199. }
  200. case VIDIOCSTUNER:
  201. {
  202. struct video_tuner t;
  203. if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) )
  204. return -EFAULT;
  205. if ( t.tuner )
  206. return -EINVAL;
  207. return 0;
  208. }
  209. case VIDIOCGFREQ:
  210. return put_user( card->current_frequency, (u32 *)arg );
  211. case VIDIOCSFREQ:
  212. {
  213. u32 frequency;
  214.  
  215. if ( get_user( frequency, (u32 *)arg ) )
  216. return -EFAULT;
  217. if ( (frequency < GEMTEK_PCI_RANGE_LOW) || (frequency > GEMTEK_PCI_RANGE_HIGH) )
  218. return -EINVAL;
  219. gemtek_pci_setfrequency( card, frequency );
  220. card->current_frequency = frequency;
  221. card->mute = FALSE;
  222. return 0;
  223. }
  224.   
  225. case VIDIOCGAUDIO:
  226. {
  227. struct video_audio a;
  228. memset( &a, 0, sizeof( a ) );
  229. a.flags |= VIDEO_AUDIO_MUTABLE;
  230. a.volume = 1;
  231. a.step = 65535;
  232.                         a.mode = (1 << gemtek_pci_getsignal( card ));
  233. strcpy( a.name, "Radio" );
  234. if ( copy_to_user( arg, &a, sizeof( struct video_audio ) ) )
  235. return -EFAULT;
  236. return 0;
  237. }
  238. case VIDIOCSAUDIO:
  239. {
  240. struct video_audio a;
  241. if ( copy_from_user( &a, arg, sizeof( struct video_audio ) ) ) 
  242. return -EFAULT;
  243. if ( a.audio ) 
  244. return -EINVAL;
  245. if ( a.flags & VIDEO_AUDIO_MUTE ) 
  246. gemtek_pci_mute( card );
  247. else
  248. gemtek_pci_unmute( card );
  249. return 0;
  250. }
  251. default:
  252. return -ENOIOCTLCMD;
  253. }
  254. }
  255. enum {
  256. GEMTEK_PR103
  257. };
  258. static char *card_names[] __devinitdata = {
  259. "GEMTEK_PR103"
  260. };
  261. static struct pci_device_id gemtek_pci_id[] =
  262. {
  263. { PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103,
  264.   PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 },
  265. { 0 }
  266. };
  267. MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
  268. static u8 mx = 1;
  269. static char gemtek_pci_videodev_name[] = "Gemtek PCI Radio";
  270. static inline void gemtek_pci_init_struct( struct video_device *dev )
  271. {
  272. memset( dev, 0, sizeof( struct video_device ) );
  273. dev->owner = THIS_MODULE;
  274. strcpy( dev->name , gemtek_pci_videodev_name );
  275. dev->type = VID_TYPE_TUNER;
  276. dev->hardware = VID_HARDWARE_GEMTEK;
  277. dev->open = gemtek_pci_open;
  278. dev->close = gemtek_pci_close;
  279. dev->ioctl = gemtek_pci_ioctl;
  280. }
  281. static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
  282. {
  283. struct gemtek_pci_card *card;
  284. struct video_device *devradio;
  285. if ( (card = kmalloc( sizeof( struct gemtek_pci_card ), GFP_KERNEL )) == NULL ) {
  286. printk( KERN_ERR "gemtek_pci: out of memoryn" );
  287. return -ENOMEM;
  288. }
  289. memset( card, 0, sizeof( struct gemtek_pci_card ) );
  290. if ( pci_enable_device( pci_dev ) ) 
  291. goto err_pci;
  292. card->iobase = pci_resource_start( pci_dev, 0 );
  293. card->length = pci_resource_len( pci_dev, 0 );
  294. if ( request_region( card->iobase, card->length, card_names[pci_id->driver_data] ) == NULL ) {
  295. printk( KERN_ERR "gemtek_pci: i/o port already in usen" );
  296. goto err_pci;
  297. }
  298. pci_read_config_byte( pci_dev, PCI_REVISION_ID, &card->chiprev );
  299. pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
  300. pci_set_drvdata( pci_dev, card );
  301.  
  302. if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
  303. printk( KERN_ERR "gemtek_pci: out of memoryn" );
  304. goto err_video;
  305. }
  306. gemtek_pci_init_struct( devradio );
  307. if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) {
  308. kfree( devradio );
  309. goto err_video;
  310. }
  311. card->videodev = devradio;
  312. devradio->priv = card;
  313. gemtek_pci_mute( card );
  314. printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.n", 
  315. card->chiprev, card->iobase, card->iobase + card->length - 1 );
  316. return 0;
  317. err_video:
  318. release_region( card->iobase, card->length );
  319. err_pci:
  320. kfree( card );
  321. return -ENODEV;        
  322. }
  323. static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
  324. {
  325. struct gemtek_pci_card *card = pci_get_drvdata( pci_dev );
  326. video_unregister_device( card->videodev );
  327. kfree( card->videodev );
  328. release_region( card->iobase, card->length );
  329. if ( mx )
  330. gemtek_pci_mute( card );
  331. kfree( card );
  332. pci_set_drvdata( pci_dev, NULL );
  333. }
  334. static struct pci_driver gemtek_pci_driver =
  335. {
  336.     name: "gemtek_pci",
  337. id_table: gemtek_pci_id,
  338.    probe: gemtek_pci_probe,
  339.   remove: __devexit_p(gemtek_pci_remove),
  340. };
  341. static int __init gemtek_pci_init_module( void )
  342. {
  343. return pci_module_init( &gemtek_pci_driver );
  344. }
  345. static void __exit gemtek_pci_cleanup_module( void )
  346. {
  347. return pci_unregister_driver( &gemtek_pci_driver );
  348. }
  349. MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" );
  350. MODULE_DESCRIPTION( "The video4linux driver for the Gemtek PCI Radio Card" );
  351. MODULE_LICENSE("GPL");
  352. MODULE_PARM( mx, "b" );
  353. MODULE_PARM_DESC( mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not" );
  354. MODULE_PARM( nr_radio, "i");
  355. MODULE_PARM_DESC( nr_radio, "video4linux device number to use");
  356. EXPORT_NO_SYMBOLS;
  357. module_init( gemtek_pci_init_module );
  358. module_exit( gemtek_pci_cleanup_module );