File: /usr/src/linux/drivers/media/radio/radio-gemtek-pci.c

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     
40     #include <linux/version.h>
41     #include <linux/config.h>
42     #include <linux/types.h>
43     #include <linux/list.h>
44     #include <linux/module.h>
45     #include <linux/init.h>
46     #include <linux/pci.h>
47     #include <linux/videodev.h>
48     #include <linux/errno.h>
49     
50     #include <asm/io.h>
51     #include <asm/uaccess.h>
52     
53     #ifndef PCI_VENDOR_ID_GEMTEK
54     #define PCI_VENDOR_ID_GEMTEK 0x5046
55     #endif
56     
57     #ifndef PCI_DEVICE_ID_GEMTEK_PR103
58     #define PCI_DEVICE_ID_GEMTEK_PR103 0x1001
59     #endif
60     
61     #ifndef GEMTEK_PCI_RANGE_LOW
62     #define GEMTEK_PCI_RANGE_LOW (87*16000)
63     #endif
64     
65     #ifndef GEMTEK_PCI_RANGE_HIGH
66     #define GEMTEK_PCI_RANGE_HIGH (108*16000)
67     #endif
68     
69     #ifndef TRUE
70     #define TRUE (1)
71     #endif
72     
73     #ifndef FALSE 
74     #define FALSE (0)
75     #endif
76     
77     struct gemtek_pci_card {
78     	struct video_device *videodev;
79     	
80     	u32 iobase;
81     	u32 length;
82     	u8  chiprev;
83     	u16 model;
84     	
85     	u32 current_frequency;
86     	u8  mute;
87     };
88     
89     static const char rcsid[] = "$Id: radio-gemtek-pci.c,v 1.1 2001/07/23 08:08:16 ted Exp ted $";
90     
91     static int nr_radio = -1;
92     
93     static int gemtek_pci_open( struct video_device *dev, int flags)
94     {
95     	struct gemtek_pci_card *card =  dev->priv;
96     
97     /* Paranoid check */
98     	if ( !card )
99     		return -ENODEV;
100     
101     	return 0;
102     }
103     
104     static void gemtek_pci_close( struct video_device *dev )
105     {
106     /*
107      *  The module usage is managed by 'videodev'
108      */
109     }
110     
111     static inline u8 gemtek_pci_out( u16 value, u32 port )
112     {
113     	outw( value, port );
114     
115     	return (u8)value;
116     }
117     
118     #define _b0( v ) *((u8 *)&v)  
119     static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
120     {
121     	register u8 byte = *last_byte;
122     
123     	if ( !value ) {
124     		if ( !keep )
125     			value = (u16)port;
126     		byte &= 0xfd;	
127     	} else
128     		byte |= 2;
129     
130     	_b0( value ) = byte;
131     	outw( value, port );
132     	byte |= 1;
133     	_b0( value ) = byte;
134     	outw( value, port );
135     	byte &= 0xfe;
136     	_b0( value ) = byte;
137     	outw( value, port );
138     	
139     	*last_byte = byte;
140     }
141     
142     static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
143     {
144     	__gemtek_pci_cmd( 0x00, port, last_byte, FALSE );
145     }
146     
147     static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
148     {
149     	__gemtek_pci_cmd( cmd, port, last_byte, TRUE );
150     }
151     
152     static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
153     {
154     	register int i;
155     	register u32 value = frequency / 200 + 856;
156     	register u16 mask = 0x8000;
157     	u8 last_byte;
158     	u32 port = card->iobase;
159     
160     	last_byte = gemtek_pci_out( 0x06, port );
161     
162     	i = 0;
163     	do {
164     		gemtek_pci_nil( port, &last_byte );
165     		i++;
166     	} while ( i < 9 );
167     
168     	i = 0;
169     	do {
170     		gemtek_pci_cmd( value & mask, port, &last_byte );
171     		mask >>= 1;
172     		i++;
173     	} while ( i < 16 );
174     
175     	outw( 0x10, port );
176     }
177     
178     
179     static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
180     {
181     	outb( 0x1f, card->iobase );
182     	card->mute = TRUE;
183     }
184     
185     static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
186     {
187     	if ( card->mute ) {
188     		gemtek_pci_setfrequency( card, card->current_frequency );
189     		card->mute = FALSE;
190     	}
191     }
192     
193     static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card )
194     {
195     	return ( inb( card->iobase ) & 0x08 ) ? 0 : 1;
196     }
197     
198     static int gemtek_pci_ioctl( struct video_device *dev, unsigned int cmd, void *arg)
199     {
200     	struct gemtek_pci_card *card = dev->priv;
201     
202     	switch ( cmd ) {
203     		case VIDIOCGCAP:
204     		{
205     			struct video_capability c;
206     
207     			c.type = VID_TYPE_TUNER;
208     			c.channels = 1;
209     			c.audios = 1;
210     			c.maxwidth = 0;
211     			c.maxheight = 0;
212     			c.minwidth = 0;
213     			c.minheight = 0;
214     			strcpy( c.name, "Gemtek PCI Radio" );
215     			if ( copy_to_user( arg, &c, sizeof( c ) ) )
216     				return -EFAULT;
217     
218     			return 0;
219     		} 
220     
221     		case VIDIOCGTUNER:
222     		{
223     			struct video_tuner t;
224     
225     			if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) )
226     				return -EFAULT;
227     
228     			if ( t.tuner ) 
229     				return -EINVAL;
230     
231     			t.rangelow = GEMTEK_PCI_RANGE_LOW;
232     			t.rangehigh = GEMTEK_PCI_RANGE_HIGH;
233     			t.flags = VIDEO_TUNER_LOW;
234     			t.mode = VIDEO_MODE_AUTO;
235     			t.signal = 0xFFFF * gemtek_pci_getsignal( card );
236     			strcpy( t.name, "FM" );
237     
238     			if ( copy_to_user( arg, &t, sizeof( struct video_tuner ) ) )
239     				return -EFAULT;
240     
241     			return 0;
242     		}
243     
244     		case VIDIOCSTUNER:
245     		{
246     			struct video_tuner t;
247     
248     			if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) )
249     				return -EFAULT;
250     
251     			if ( t.tuner )
252     				return -EINVAL;
253     
254     			return 0;
255     		}
256     
257     		case VIDIOCGFREQ:
258     			return put_user( card->current_frequency, (u32 *)arg );
259     
260     		case VIDIOCSFREQ:
261     		{
262     			u32 frequency;
263     	 
264     			if ( get_user( frequency, (u32 *)arg ) )
265     				return -EFAULT;
266     
267     			if ( (frequency < GEMTEK_PCI_RANGE_LOW) || (frequency > GEMTEK_PCI_RANGE_HIGH) )
268     				return -EINVAL;
269     
270     			gemtek_pci_setfrequency( card, frequency );
271     			card->current_frequency = frequency;
272     			card->mute = FALSE;
273     
274     			return 0;
275     		}
276       
277     		case VIDIOCGAUDIO:
278     		{	
279     			struct video_audio a;
280     
281     			memset( &a, 0, sizeof( a ) );
282     			a.flags |= VIDEO_AUDIO_MUTABLE;
283     			a.volume = 1;
284     			a.step = 65535;
285     			strcpy( a.name, "Radio" );
286     
287     			if ( copy_to_user( arg, &a, sizeof( struct video_audio ) ) )
288     				return -EFAULT;
289     
290     			return 0;			
291     		}
292     
293     		case VIDIOCSAUDIO:
294     		{
295     			struct video_audio a;
296     
297     			if ( copy_from_user( &a, arg, sizeof( struct video_audio ) ) ) 
298     				return -EFAULT;	
299     
300     			if ( a.audio ) 
301     				return -EINVAL;
302     
303     			if ( a.flags & VIDEO_AUDIO_MUTE ) 
304     				gemtek_pci_mute( card );
305     
306     			else
307     				gemtek_pci_unmute( card );
308     
309     			return 0;
310     		}
311     
312     		default:
313     			return -ENOIOCTLCMD;
314     	}
315     }
316     
317     enum {
318     	GEMTEK_PR103
319     };
320     
321     static char *card_names[] __devinitdata = {
322     	"GEMTEK_PR103"
323     };
324     
325     static struct pci_device_id gemtek_pci_id[] =
326     {
327     	{ PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103,
328     	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 },
329     	{ 0 }
330     };
331     
332     MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
333     
334     static u8 mx = 1;
335     
336     static char gemtek_pci_videodev_name[] = "Gemtek PCI Radio";
337     
338     static inline void gemtek_pci_init_struct( struct video_device *dev )
339     {
340     	memset( dev, 0, sizeof( struct video_device ) );
341     	dev->owner = THIS_MODULE;
342     	strcpy( dev->name , gemtek_pci_videodev_name );
343     	dev->type = VID_TYPE_TUNER;
344     	dev->hardware = VID_HARDWARE_GEMTEK;
345     	dev->open = gemtek_pci_open;
346     	dev->close = gemtek_pci_close;
347     	dev->ioctl = gemtek_pci_ioctl;
348     }
349     
350     static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
351     {
352     	struct gemtek_pci_card *card;
353     	struct video_device *devradio;
354     
355     	if ( (card = kmalloc( sizeof( struct gemtek_pci_card ), GFP_KERNEL )) == NULL ) {
356     		printk( KERN_ERR "gemtek_pci: out of memory\n" );
357     		return -ENOMEM;
358     	}
359     	memset( card, 0, sizeof( struct gemtek_pci_card ) );
360     
361     	if ( pci_enable_device( pci_dev ) ) 
362     		goto err_pci;
363     	
364     	card->iobase = pci_resource_start( pci_dev, 0 );
365     	card->length = pci_resource_len( pci_dev, 0 );
366     
367     	if ( request_region( card->iobase, card->length, card_names[pci_id->driver_data] ) == NULL ) {
368     		printk( KERN_ERR "gemtek_pci: i/o port already in use\n" );
369     		goto err_pci;
370     	}
371     
372     	pci_read_config_byte( pci_dev, PCI_REVISION_ID, &card->chiprev );
373     	pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
374     
375     	pci_set_drvdata( pci_dev, card );
376      
377     	if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
378     		printk( KERN_ERR "gemtek_pci: out of memory\n" );
379     		goto err_video;
380     	}
381     	gemtek_pci_init_struct( devradio );
382     
383     	if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) {
384     		kfree( devradio );
385     		goto err_video;
386     	}
387     
388     	card->videodev = devradio;
389     	devradio->priv = card;
390     	gemtek_pci_mute( card );
391     
392     	printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", 
393     		card->chiprev, card->iobase, card->iobase + card->length - 1 );
394     
395     	return 0;
396     
397     err_video:
398     	release_region( card->iobase, card->length );
399     
400     err_pci:
401     	kfree( card );
402     	return -ENODEV;        
403     }
404     
405     static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
406     {
407     	struct gemtek_pci_card *card = pci_get_drvdata( pci_dev );
408     
409     	video_unregister_device( card->videodev );
410     	kfree( card->videodev );
411     
412     	release_region( card->iobase, card->length );
413     	
414     	if ( mx )
415     		gemtek_pci_mute( card );
416     
417     	kfree( card );
418     	
419     	pci_set_drvdata( pci_dev, NULL );
420     }
421     
422     static struct pci_driver gemtek_pci_driver =
423     {
424         name:	"gemtek_pci",
425     id_table:	gemtek_pci_id,
426        probe:	gemtek_pci_probe,
427       remove:	gemtek_pci_remove
428     };
429     
430     static int __init gemtek_pci_init_module( void )
431     {
432     	return pci_module_init( &gemtek_pci_driver );
433     }
434     
435     static void __exit gemtek_pci_cleanup_module( void )
436     {
437     	return pci_unregister_driver( &gemtek_pci_driver );
438     }
439     
440     MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" );
441     MODULE_DESCRIPTION( "The video4linux driver for the Gemtek PCI Radio Card" );
442     MODULE_PARM( mx, "b" );
443     MODULE_PARM_DESC( mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not" );
444     MODULE_PARM( nr_radio, "i");
445     MODULE_PARM_DESC( nr_radio, "video4linux device number to use");
446     
447     EXPORT_NO_SYMBOLS;
448     
449     module_init( gemtek_pci_init_module );
450     module_exit( gemtek_pci_cleanup_module );
451     
452