2006-04-08 23:06:16 +04:00
/*
* Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
2005-04-17 02:20:36 +04:00
* ( C ) 2001 Dimitromanolakis Apostolos < apdim @ grecian . net >
*
* Based in the radio Maestro PCI driver . Actually it uses the same chip
* for radio but different pci controller .
*
* I didn ' t have any specs I reversed engineered the protocol from
2006-04-08 23:06:16 +04:00
* the windows driver ( radio . dll ) .
2005-04-17 02:20:36 +04:00
*
* The card uses the TEA5757 chip that includes a search function but it
2006-04-08 23:06:16 +04:00
* is useless as I haven ' t found any way to read back the frequency . If
2005-04-17 02:20:36 +04:00
* anybody does please mail me .
*
* For the pdf file see :
* http : //www.semiconductors.philips.com/pip/TEA5757H/V1
*
*
* CHANGES :
* 0.75 b
* - better pci interface thanks to Francois Romieu < romieu @ cogenit . fr >
*
2006-08-08 16:10:05 +04:00
* 0.75 Sun Feb 4 22 : 51 : 27 EET 2001
2005-04-17 02:20:36 +04:00
* - tiding up
* - removed support for multiple devices as it didn ' t work anyway
*
2006-04-08 23:06:16 +04:00
* BUGS :
2005-04-17 02:20:36 +04:00
* - card unmutes if you change frequency
*
2007-01-25 15:04:34 +03:00
* ( c ) 2006 , 2007 by Mauro Carvalho Chehab < mchehab @ infradead . org > :
* - Conversion to V4L2 API
* - Uses video_ioctl2 for parsing and to add debug support
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/ioport.h>
# include <linux/delay.h>
2006-02-07 11:49:14 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <linux/pci.h>
2006-08-08 16:10:05 +04:00
# include <linux/videodev2.h>
2009-03-06 19:51:33 +03:00
# include <linux/version.h> /* for KERNEL_VERSION MACRO */
# include <linux/io.h>
# include <media/v4l2-device.h>
2008-07-20 15:12:02 +04:00
# include <media/v4l2-ioctl.h>
2005-04-17 02:20:36 +04:00
2009-03-06 19:51:33 +03:00
MODULE_AUTHOR ( " Dimitromanolakis Apostolos, apdim@grecian.net " ) ;
MODULE_DESCRIPTION ( " Radio driver for the Guillemot Maxi Radio FM2000 radio. " ) ;
MODULE_LICENSE ( " GPL " ) ;
static int radio_nr = - 1 ;
module_param ( radio_nr , int , 0 ) ;
static int debug ;
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " activates debug info " ) ;
2007-01-26 13:23:44 +03:00
# define DRIVER_VERSION "0.77"
2006-08-08 16:10:05 +04:00
2009-03-06 19:51:33 +03:00
# define RADIO_VERSION KERNEL_VERSION(0, 7, 7)
# define dprintk(dev, num, fmt, arg...) \
v4l2_dbg ( num , debug , & dev - > v4l2_dev , fmt , # # arg )
2005-04-17 02:20:36 +04:00
# ifndef PCI_VENDOR_ID_GUILLEMOT
# define PCI_VENDOR_ID_GUILLEMOT 0x5046
# endif
# ifndef PCI_DEVICE_ID_GUILLEMOT
# define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
# endif
/* TEA5757 pin mappings */
2009-03-06 19:51:33 +03:00
static const int clk = 1 , data = 2 , wren = 4 , mo_st = 8 , power = 16 ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:51:33 +03:00
# define FREQ_LO (50 * 16000)
# define FREQ_HI (150 * 16000)
2005-04-17 02:20:36 +04:00
# define FREQ_IF 171200 /* 10.7*16000 */
# define FREQ_STEP 200 /* 12.5*16 */
2007-01-26 13:23:44 +03:00
/* (x==fmhz*16*1000) -> bits */
2009-03-06 19:51:33 +03:00
# define FREQ2BITS(x) \
( ( ( ( unsigned int ) ( x ) + FREQ_IF + ( FREQ_STEP < < 1 ) ) / ( FREQ_STEP < < 2 ) ) < < 2 )
2005-04-17 02:20:36 +04:00
# define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
2009-03-06 19:51:33 +03:00
struct maxiradio
2008-08-23 11:49:13 +04:00
{
2009-03-06 19:51:33 +03:00
struct v4l2_device v4l2_dev ;
struct video_device vdev ;
struct pci_dev * pdev ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:51:33 +03:00
u16 io ; /* base of radio io */
u16 muted ; /* VIDEO_AUDIO_MUTE */
u16 stereo ; /* VIDEO_TUNER_STEREO_ON */
u16 tuned ; /* signal strength (0 or 0xffff) */
2006-04-08 23:06:16 +04:00
2005-04-17 02:20:36 +04:00
unsigned long freq ;
2006-04-08 23:06:16 +04:00
2006-02-07 11:49:14 +03:00
struct mutex lock ;
2007-01-26 13:33:07 +03:00
} ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:51:33 +03:00
static inline struct maxiradio * to_maxiradio ( struct v4l2_device * v4l2_dev )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:51:33 +03:00
return container_of ( v4l2_dev , struct maxiradio , v4l2_dev ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:51:33 +03:00
static void outbit ( unsigned long bit , u16 io )
{
int val = power | wren | ( bit ? data : 0 ) ;
outb ( val , io ) ;
udelay ( 4 ) ;
outb ( val | clk , io ) ;
udelay ( 4 ) ;
outb ( val , io ) ;
udelay ( 4 ) ;
}
static void turn_power ( struct maxiradio * dev , int p )
2005-04-17 02:20:36 +04:00
{
2007-01-26 13:23:44 +03:00
if ( p ! = 0 ) {
2009-03-06 19:51:33 +03:00
dprintk ( dev , 1 , " Radio powered on \n " ) ;
outb ( power , dev - > io ) ;
2007-01-26 13:23:44 +03:00
} else {
2009-03-06 19:51:33 +03:00
dprintk ( dev , 1 , " Radio powered off \n " ) ;
outb ( 0 , dev - > io ) ;
2007-01-26 13:23:44 +03:00
}
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:51:33 +03:00
static void set_freq ( struct maxiradio * dev , u32 freq )
2005-04-17 02:20:36 +04:00
{
unsigned long int si ;
int bl ;
2009-03-06 19:51:33 +03:00
int io = dev - > io ;
2008-09-04 00:11:54 +04:00
int val = FREQ2BITS ( freq ) ;
2006-04-08 23:06:16 +04:00
2005-04-17 02:20:36 +04:00
/* TEA5757 shift register bits (see pdf) */
2008-09-04 00:11:54 +04:00
outbit ( 0 , io ) ; /* 24 search */
outbit ( 1 , io ) ; /* 23 search up/down */
2006-04-08 23:06:16 +04:00
2008-09-04 00:11:54 +04:00
outbit ( 0 , io ) ; /* 22 stereo/mono */
2005-04-17 02:20:36 +04:00
2008-09-04 00:11:54 +04:00
outbit ( 0 , io ) ; /* 21 band */
outbit ( 0 , io ) ; /* 20 band (only 00=FM works I think) */
2005-04-17 02:20:36 +04:00
2008-09-04 00:11:54 +04:00
outbit ( 0 , io ) ; /* 19 port ? */
outbit ( 0 , io ) ; /* 18 port ? */
2006-04-08 23:06:16 +04:00
2008-09-04 00:11:54 +04:00
outbit ( 0 , io ) ; /* 17 search level */
outbit ( 0 , io ) ; /* 16 search level */
2006-04-08 23:06:16 +04:00
2005-04-17 02:20:36 +04:00
si = 0x8000 ;
2008-09-04 00:11:54 +04:00
for ( bl = 1 ; bl < = 16 ; bl + + ) {
outbit ( val & si , io ) ;
si > > = 1 ;
2007-01-26 13:23:44 +03:00
}
2006-04-08 23:06:16 +04:00
2009-03-06 19:51:33 +03:00
dprintk ( dev , 1 , " Radio freq set to %d.%02d MHz \n " ,
2007-01-26 13:23:44 +03:00
freq / 16000 ,
freq % 16000 * 100 / 16000 ) ;
2009-03-06 19:51:33 +03:00
turn_power ( dev , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:51:33 +03:00
static int get_stereo ( u16 io )
2006-04-08 23:06:16 +04:00
{
2007-01-26 13:23:44 +03:00
outb ( power , io ) ;
udelay ( 4 ) ;
2005-04-17 02:20:36 +04:00
return ! ( inb ( io ) & mo_st ) ;
}
2009-03-06 19:51:33 +03:00
static int get_tune ( u16 io )
2006-04-08 23:06:16 +04:00
{
2007-01-26 13:23:44 +03:00
outb ( power + clk , io ) ;
udelay ( 4 ) ;
2005-04-17 02:20:36 +04:00
return ! ( inb ( io ) & mo_st ) ;
}
2009-03-06 19:51:33 +03:00
static int vidioc_querycap ( struct file * file , void * priv ,
2007-01-25 15:04:34 +03:00
struct v4l2_capability * v )
{
2009-03-06 19:51:33 +03:00
struct maxiradio * dev = video_drvdata ( file ) ;
2007-01-25 15:04:34 +03:00
2009-03-06 19:51:33 +03:00
strlcpy ( v - > driver , " radio-maxiradio " , sizeof ( v - > driver ) ) ;
strlcpy ( v - > card , " Maxi Radio FM2000 radio " , sizeof ( v - > card ) ) ;
snprintf ( v - > bus_info , sizeof ( v - > bus_info ) , " PCI:%s " , pci_name ( dev - > pdev ) ) ;
v - > version = RADIO_VERSION ;
v - > capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO ;
2007-01-25 15:04:34 +03:00
return 0 ;
}
2009-03-06 19:51:33 +03:00
static int vidioc_g_tuner ( struct file * file , void * priv ,
2007-01-25 15:04:34 +03:00
struct v4l2_tuner * v )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:51:33 +03:00
struct maxiradio * dev = video_drvdata ( file ) ;
2005-04-17 02:20:36 +04:00
2007-01-25 15:04:34 +03:00
if ( v - > index > 0 )
return - EINVAL ;
2006-08-08 16:10:05 +04:00
2009-03-06 19:51:33 +03:00
mutex_lock ( & dev - > lock ) ;
strlcpy ( v - > name , " FM " , sizeof ( v - > name ) ) ;
2007-01-25 15:04:34 +03:00
v - > type = V4L2_TUNER_RADIO ;
2009-03-06 19:51:33 +03:00
v - > rangelow = FREQ_LO ;
v - > rangehigh = FREQ_HI ;
v - > rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO ;
v - > capability = V4L2_TUNER_CAP_LOW ;
if ( get_stereo ( dev - > io ) )
2007-01-25 15:04:34 +03:00
v - > audmode = V4L2_TUNER_MODE_STEREO ;
else
v - > audmode = V4L2_TUNER_MODE_MONO ;
2009-03-06 19:51:33 +03:00
v - > signal = 0xffff * get_tune ( dev - > io ) ;
mutex_unlock ( & dev - > lock ) ;
2006-04-08 23:06:16 +04:00
2007-01-25 15:04:34 +03:00
return 0 ;
}
2006-08-08 16:10:05 +04:00
2009-03-06 19:51:33 +03:00
static int vidioc_s_tuner ( struct file * file , void * priv ,
2007-01-25 15:04:34 +03:00
struct v4l2_tuner * v )
{
2009-03-06 19:51:33 +03:00
return v - > index ? - EINVAL : 0 ;
2007-01-25 21:00:45 +03:00
}
2007-01-25 22:48:13 +03:00
static int vidioc_g_input ( struct file * filp , void * priv , unsigned int * i )
{
* i = 0 ;
return 0 ;
}
static int vidioc_s_input ( struct file * filp , void * priv , unsigned int i )
{
2009-03-06 19:51:33 +03:00
return i ? - EINVAL : 0 ;
}
2007-01-26 13:23:44 +03:00
2009-03-06 19:51:33 +03:00
static int vidioc_g_audio ( struct file * file , void * priv ,
struct v4l2_audio * a )
{
a - > index = 0 ;
strlcpy ( a - > name , " Radio " , sizeof ( a - > name ) ) ;
a - > capability = V4L2_AUDCAP_STEREO ;
2007-01-25 22:48:13 +03:00
return 0 ;
}
2009-03-06 19:51:33 +03:00
static int vidioc_s_audio ( struct file * file , void * priv ,
2007-01-25 21:00:45 +03:00
struct v4l2_audio * a )
{
2009-03-06 19:51:33 +03:00
return a - > index ? - EINVAL : 0 ;
2007-01-25 21:00:45 +03:00
}
2009-03-06 19:51:33 +03:00
static int vidioc_s_frequency ( struct file * file , void * priv ,
2007-01-25 15:04:34 +03:00
struct v4l2_frequency * f )
{
2009-03-06 19:51:33 +03:00
struct maxiradio * dev = video_drvdata ( file ) ;
2006-04-08 23:06:16 +04:00
2009-11-27 10:33:25 +03:00
if ( f - > tuner ! = 0 | | f - > type ! = V4L2_TUNER_RADIO )
return - EINVAL ;
2007-01-26 13:23:44 +03:00
if ( f - > frequency < FREQ_LO | | f - > frequency > FREQ_HI ) {
2009-03-06 19:51:33 +03:00
dprintk ( dev , 1 , " radio freq (%d.%02d MHz) out of range (%d-%d) \n " ,
2007-01-26 13:23:44 +03:00
f - > frequency / 16000 ,
f - > frequency % 16000 * 100 / 16000 ,
FREQ_LO / 16000 , FREQ_HI / 16000 ) ;
2007-01-25 15:04:34 +03:00
return - EINVAL ;
2007-01-26 13:23:44 +03:00
}
2006-04-08 23:06:16 +04:00
2009-03-06 19:51:33 +03:00
mutex_lock ( & dev - > lock ) ;
dev - > freq = f - > frequency ;
set_freq ( dev , dev - > freq ) ;
2007-01-25 15:04:34 +03:00
msleep ( 125 ) ;
2009-03-06 19:51:33 +03:00
mutex_unlock ( & dev - > lock ) ;
2006-08-08 16:10:05 +04:00
2007-01-25 15:04:34 +03:00
return 0 ;
}
2006-04-08 23:06:16 +04:00
2009-03-06 19:51:33 +03:00
static int vidioc_g_frequency ( struct file * file , void * priv ,
2007-01-25 15:04:34 +03:00
struct v4l2_frequency * f )
{
2009-03-06 19:51:33 +03:00
struct maxiradio * dev = video_drvdata ( file ) ;
2006-04-08 23:06:16 +04:00
2009-11-27 10:33:25 +03:00
if ( f - > tuner ! = 0 )
return - EINVAL ;
2007-01-25 15:04:34 +03:00
f - > type = V4L2_TUNER_RADIO ;
2009-03-06 19:51:33 +03:00
f - > frequency = dev - > freq ;
2007-01-25 15:04:34 +03:00
2009-03-06 19:51:33 +03:00
dprintk ( dev , 4 , " radio freq is %d.%02d MHz " ,
2007-01-26 13:23:44 +03:00
f - > frequency / 16000 ,
f - > frequency % 16000 * 100 / 16000 ) ;
2007-01-25 15:04:34 +03:00
return 0 ;
}
2009-03-06 19:51:33 +03:00
static int vidioc_queryctrl ( struct file * file , void * priv ,
2007-01-25 15:04:34 +03:00
struct v4l2_queryctrl * qc )
{
2009-03-06 19:51:33 +03:00
switch ( qc - > id ) {
case V4L2_CID_AUDIO_MUTE :
return v4l2_ctrl_query_fill ( qc , 0 , 1 , 1 , 1 ) ;
2007-01-25 15:04:34 +03:00
}
return - EINVAL ;
}
2006-08-08 16:10:05 +04:00
2009-03-06 19:51:33 +03:00
static int vidioc_g_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
2007-01-25 15:04:34 +03:00
{
2009-03-06 19:51:33 +03:00
struct maxiradio * dev = video_drvdata ( file ) ;
2006-08-08 16:10:05 +04:00
2007-01-25 15:04:34 +03:00
switch ( ctrl - > id ) {
2009-03-06 19:51:33 +03:00
case V4L2_CID_AUDIO_MUTE :
ctrl - > value = dev - > muted ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-01-26 13:23:44 +03:00
2007-01-25 15:04:34 +03:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:51:33 +03:00
static int vidioc_s_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:51:33 +03:00
struct maxiradio * dev = video_drvdata ( file ) ;
2006-04-08 23:06:16 +04:00
2007-01-25 15:04:34 +03:00
switch ( ctrl - > id ) {
2009-03-06 19:51:33 +03:00
case V4L2_CID_AUDIO_MUTE :
mutex_lock ( & dev - > lock ) ;
dev - > muted = ctrl - > value ;
if ( dev - > muted )
turn_power ( dev , 0 ) ;
else
set_freq ( dev , dev - > freq ) ;
mutex_unlock ( & dev - > lock ) ;
return 0 ;
2007-01-25 15:04:34 +03:00
}
2007-01-26 13:23:44 +03:00
2007-01-25 15:04:34 +03:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:51:33 +03:00
static const struct v4l2_file_operations maxiradio_fops = {
. owner = THIS_MODULE ,
. ioctl = video_ioctl2 ,
} ;
2008-07-21 09:57:38 +04:00
static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
2007-01-25 15:04:34 +03:00
. vidioc_querycap = vidioc_querycap ,
. vidioc_g_tuner = vidioc_g_tuner ,
. vidioc_s_tuner = vidioc_s_tuner ,
2007-01-25 21:00:45 +03:00
. vidioc_g_audio = vidioc_g_audio ,
. vidioc_s_audio = vidioc_s_audio ,
2007-01-25 22:48:13 +03:00
. vidioc_g_input = vidioc_g_input ,
. vidioc_s_input = vidioc_s_input ,
2007-01-25 15:04:34 +03:00
. vidioc_g_frequency = vidioc_g_frequency ,
. vidioc_s_frequency = vidioc_s_frequency ,
. vidioc_queryctrl = vidioc_queryctrl ,
. vidioc_g_ctrl = vidioc_g_ctrl ,
. vidioc_s_ctrl = vidioc_s_ctrl ,
} ;
2005-04-17 02:20:36 +04:00
static int __devinit maxiradio_init_one ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
2009-03-06 19:51:33 +03:00
struct maxiradio * dev ;
struct v4l2_device * v4l2_dev ;
int retval = - ENOMEM ;
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
if ( dev = = NULL ) {
dev_err ( & pdev - > dev , " not enough memory \n " ) ;
return - ENOMEM ;
}
v4l2_dev = & dev - > v4l2_dev ;
mutex_init ( & dev - > lock ) ;
dev - > pdev = pdev ;
dev - > muted = 1 ;
dev - > freq = FREQ_LO ;
strlcpy ( v4l2_dev - > name , " maxiradio " , sizeof ( v4l2_dev - > name ) ) ;
retval = v4l2_device_register ( & pdev - > dev , v4l2_dev ) ;
if ( retval < 0 ) {
v4l2_err ( v4l2_dev , " Could not register v4l2_device \n " ) ;
goto errfr ;
}
if ( ! request_region ( pci_resource_start ( pdev , 0 ) ,
2006-04-08 23:06:16 +04:00
pci_resource_len ( pdev , 0 ) , " Maxi Radio FM 2000 " ) ) {
2009-03-06 19:51:33 +03:00
v4l2_err ( v4l2_dev , " can't reserve I/O ports \n " ) ;
2006-04-08 23:06:16 +04:00
goto err_out ;
2005-04-17 02:20:36 +04:00
}
if ( pci_enable_device ( pdev ) )
2006-04-08 23:06:16 +04:00
goto err_out_free_region ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:51:33 +03:00
dev - > io = pci_resource_start ( pdev , 0 ) ;
strlcpy ( dev - > vdev . name , v4l2_dev - > name , sizeof ( dev - > vdev . name ) ) ;
dev - > vdev . v4l2_dev = v4l2_dev ;
dev - > vdev . fops = & maxiradio_fops ;
dev - > vdev . ioctl_ops = & maxiradio_ioctl_ops ;
dev - > vdev . release = video_device_release_empty ;
video_set_drvdata ( & dev - > vdev , dev ) ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:51:33 +03:00
if ( video_register_device ( & dev - > vdev , VFL_TYPE_RADIO , radio_nr ) < 0 ) {
v4l2_err ( v4l2_dev , " can't register device! " ) ;
2006-04-08 23:06:16 +04:00
goto err_out_free_region ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:51:33 +03:00
v4l2_info ( v4l2_dev , " version " DRIVER_VERSION
" time " __TIME__ " " __DATE__ " \n " ) ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:51:33 +03:00
v4l2_info ( v4l2_dev , " found Guillemot MAXI Radio device (io = 0x%x) \n " ,
dev - > io ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
err_out_free_region :
release_region ( pci_resource_start ( pdev , 0 ) , pci_resource_len ( pdev , 0 ) ) ;
err_out :
2009-03-06 19:51:33 +03:00
v4l2_device_unregister ( v4l2_dev ) ;
errfr :
kfree ( dev ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
static void __devexit maxiradio_remove_one ( struct pci_dev * pdev )
{
2009-03-06 19:51:33 +03:00
struct v4l2_device * v4l2_dev = dev_get_drvdata ( & pdev - > dev ) ;
struct maxiradio * dev = to_maxiradio ( v4l2_dev ) ;
video_unregister_device ( & dev - > vdev ) ;
v4l2_device_unregister ( & dev - > v4l2_dev ) ;
2005-04-17 02:20:36 +04:00
release_region ( pci_resource_start ( pdev , 0 ) , pci_resource_len ( pdev , 0 ) ) ;
}
static struct pci_device_id maxiradio_pci_tbl [ ] = {
{ PCI_VENDOR_ID_GUILLEMOT , PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO ,
PCI_ANY_ID , PCI_ANY_ID , } ,
2009-03-06 19:51:33 +03:00
{ 0 }
2005-04-17 02:20:36 +04:00
} ;
MODULE_DEVICE_TABLE ( pci , maxiradio_pci_tbl ) ;
static struct pci_driver maxiradio_driver = {
. name = " radio-maxiradio " ,
. id_table = maxiradio_pci_tbl ,
. probe = maxiradio_init_one ,
. remove = __devexit_p ( maxiradio_remove_one ) ,
} ;
static int __init maxiradio_radio_init ( void )
{
2005-11-30 02:59:34 +03:00
return pci_register_driver ( & maxiradio_driver ) ;
2005-04-17 02:20:36 +04:00
}
static void __exit maxiradio_radio_exit ( void )
{
pci_unregister_driver ( & maxiradio_driver ) ;
}
module_init ( maxiradio_radio_init ) ;
module_exit ( maxiradio_radio_exit ) ;