2005-04-17 02:20:36 +04:00
/* zoltrix radio plus driver for Linux radio support
* ( c ) 1998 C . van Schaik < carl @ leg . uct . ac . za >
*
2006-04-08 23:06:16 +04:00
* BUGS
2005-04-17 02:20:36 +04:00
* Due to the inconsistency in reading from the signal flags
* it is difficult to get an accurate tuned signal .
*
* It seems that the card is not linear to 0 volume . It cuts off
* at a low volume , and it is not possible ( at least I have not found )
* to get fine volume control over the low volume range .
*
* Some code derived from code by Romolo Manfredini
* romolo @ bicnet . it
*
* 1999 - 05 - 06 - ( C . van Schaik )
* - Make signal strength and stereo scans
2006-04-08 23:06:16 +04:00
* kinder to cpu while in delay
2005-04-17 02:20:36 +04:00
* 1999 - 01 - 05 - ( C . van Schaik )
* - Changed tuning to 1 / 160 Mhz accuracy
* - Added stereo support
* ( card defaults to stereo )
* ( can explicitly force mono on the card )
* ( can detect if station is in stereo )
* - Added unmute function
* - Reworked ioctl functions
* 2002 - 07 - 15 - Fix Stereo typo
2006-08-08 16:10:04 +04:00
*
* 2006 - 07 - 24 - Converted to V4L2 API
* by Mauro Carvalho Chehab < mchehab @ infradead . org >
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h> /* Modules */
# include <linux/init.h> /* Initdata */
2005-09-13 12:25:15 +04:00
# include <linux/ioport.h> /* request_region */
2005-04-17 02:20:36 +04:00
# include <linux/delay.h> /* udelay, msleep */
2006-08-08 16:10:04 +04:00
# include <linux/videodev2.h> /* kernel radio structs */
2009-03-06 19:55:34 +03:00
# include <linux/mutex.h>
# include <linux/io.h> /* outb, outb_p */
# 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:55:34 +03:00
MODULE_AUTHOR ( " C.van Schaik " ) ;
MODULE_DESCRIPTION ( " A driver for the Zoltrix Radio Plus. " ) ;
MODULE_LICENSE ( " GPL " ) ;
2011-06-25 17:15:42 +04:00
MODULE_VERSION ( " 0.0.3 " ) ;
2006-08-08 16:10:04 +04:00
2005-04-17 02:20:36 +04:00
# ifndef CONFIG_RADIO_ZOLTRIX_PORT
# define CONFIG_RADIO_ZOLTRIX_PORT -1
# endif
static int io = CONFIG_RADIO_ZOLTRIX_PORT ;
static int radio_nr = - 1 ;
2009-03-06 19:55:34 +03:00
module_param ( io , int , 0 ) ;
MODULE_PARM_DESC ( io , " I/O address of the Zoltrix Radio Plus (0x20c or 0x30c) " ) ;
module_param ( radio_nr , int , 0 ) ;
struct zoltrix {
struct v4l2_device v4l2_dev ;
struct video_device vdev ;
int io ;
2005-04-17 02:20:36 +04:00
int curvol ;
unsigned long curfreq ;
int muted ;
unsigned int stereo ;
2006-02-07 11:49:14 +03:00
struct mutex lock ;
2005-04-17 02:20:36 +04:00
} ;
2009-03-06 19:55:34 +03:00
static struct zoltrix zoltrix_card ;
static int zol_setvol ( struct zoltrix * zol , int vol )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:55:34 +03:00
zol - > curvol = vol ;
if ( zol - > muted )
2005-04-17 02:20:36 +04:00
return 0 ;
2009-03-06 19:55:34 +03:00
mutex_lock ( & zol - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( vol = = 0 ) {
2009-03-06 19:55:34 +03:00
outb ( 0 , zol - > io ) ;
outb ( 0 , zol - > io ) ;
inb ( zol - > io + 3 ) ; /* Zoltrix needs to be read to confirm */
mutex_unlock ( & zol - > lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-03-06 19:55:34 +03:00
outb ( zol - > curvol - 1 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
msleep ( 10 ) ;
2009-03-06 19:55:34 +03:00
inb ( zol - > io + 2 ) ;
mutex_unlock ( & zol - > lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-03-06 19:55:34 +03:00
static void zol_mute ( struct zoltrix * zol )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:55:34 +03:00
zol - > muted = 1 ;
mutex_lock ( & zol - > lock ) ;
outb ( 0 , zol - > io ) ;
outb ( 0 , zol - > io ) ;
inb ( zol - > io + 3 ) ; /* Zoltrix needs to be read to confirm */
mutex_unlock ( & zol - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:55:34 +03:00
static void zol_unmute ( struct zoltrix * zol )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:55:34 +03:00
zol - > muted = 0 ;
zol_setvol ( zol , zol - > curvol ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:55:34 +03:00
static int zol_setfreq ( struct zoltrix * zol , unsigned long freq )
2005-04-17 02:20:36 +04:00
{
/* tunes the radio to the desired frequency */
2009-03-06 19:55:34 +03:00
struct v4l2_device * v4l2_dev = & zol - > v4l2_dev ;
2005-04-17 02:20:36 +04:00
unsigned long long bitmask , f , m ;
2009-03-06 19:55:34 +03:00
unsigned int stereo = zol - > stereo ;
2005-04-17 02:20:36 +04:00
int i ;
2008-10-09 20:46:59 +04:00
if ( freq = = 0 ) {
2009-03-06 19:55:34 +03:00
v4l2_warn ( v4l2_dev , " cannot set a frequency of 0. \n " ) ;
2008-10-09 20:46:59 +04:00
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
m = ( freq / 160 - 8800 ) * 2 ;
2009-03-06 19:55:34 +03:00
f = ( unsigned long long ) m + 0x4d1c ;
2005-04-17 02:20:36 +04:00
bitmask = 0xc480402c10080000ull ;
i = 45 ;
2009-03-06 19:55:34 +03:00
mutex_lock ( & zol - > lock ) ;
2006-04-08 23:06:16 +04:00
2009-03-06 19:55:34 +03:00
zol - > curfreq = freq ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:55:34 +03:00
outb ( 0 , zol - > io ) ;
outb ( 0 , zol - > io ) ;
inb ( zol - > io + 3 ) ; /* Zoltrix needs to be read to confirm */
2005-04-17 02:20:36 +04:00
2009-03-06 19:55:34 +03:00
outb ( 0x40 , zol - > io ) ;
outb ( 0xc0 , zol - > io ) ;
bitmask = ( bitmask ^ ( ( f & 0xff ) < < 47 ) ^ ( ( f & 0xff00 ) < < 30 ) ^ ( stereo < < 31 ) ) ;
2005-04-17 02:20:36 +04:00
while ( i - - ) {
if ( ( bitmask & 0x8000000000000000ull ) ! = 0 ) {
2009-03-06 19:55:34 +03:00
outb ( 0x80 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
udelay ( 50 ) ;
2009-03-06 19:55:34 +03:00
outb ( 0x00 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
udelay ( 50 ) ;
2009-03-06 19:55:34 +03:00
outb ( 0x80 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
udelay ( 50 ) ;
} else {
2009-03-06 19:55:34 +03:00
outb ( 0xc0 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
udelay ( 50 ) ;
2009-03-06 19:55:34 +03:00
outb ( 0x40 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
udelay ( 50 ) ;
2009-03-06 19:55:34 +03:00
outb ( 0xc0 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
udelay ( 50 ) ;
}
bitmask * = 2 ;
}
/* termination sequence */
2009-03-06 19:55:34 +03:00
outb ( 0x80 , zol - > io ) ;
outb ( 0xc0 , zol - > io ) ;
outb ( 0x40 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
udelay ( 1000 ) ;
2009-03-06 19:55:34 +03:00
inb ( zol - > io + 2 ) ;
2005-04-17 02:20:36 +04:00
2006-04-08 23:06:16 +04:00
udelay ( 1000 ) ;
2009-03-06 19:55:34 +03:00
if ( zol - > muted ) {
outb ( 0 , zol - > io ) ;
outb ( 0 , zol - > io ) ;
inb ( zol - > io + 3 ) ;
2005-04-17 02:20:36 +04:00
udelay ( 1000 ) ;
}
2006-04-08 23:06:16 +04:00
2009-03-06 19:55:34 +03:00
mutex_unlock ( & zol - > lock ) ;
2006-04-08 23:06:16 +04:00
2009-03-06 19:55:34 +03:00
if ( ! zol - > muted )
zol_setvol ( zol , zol - > curvol ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Get signal strength */
2009-03-06 19:55:34 +03:00
static int zol_getsigstr ( struct zoltrix * zol )
2005-04-17 02:20:36 +04:00
{
int a , b ;
2009-03-06 19:55:34 +03:00
mutex_lock ( & zol - > lock ) ;
outb ( 0x00 , zol - > io ) ; /* This stuff I found to do nothing */
outb ( zol - > curvol , zol - > io ) ;
2005-04-17 02:20:36 +04:00
msleep ( 20 ) ;
2009-03-06 19:55:34 +03:00
a = inb ( zol - > io ) ;
2005-04-17 02:20:36 +04:00
msleep ( 10 ) ;
2009-03-06 19:55:34 +03:00
b = inb ( zol - > io ) ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:55:34 +03:00
mutex_unlock ( & zol - > lock ) ;
2006-04-08 23:06:16 +04:00
2005-04-17 02:20:36 +04:00
if ( a ! = b )
2009-03-06 19:55:34 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:55:34 +03:00
/* I found this out by playing with a binary scanner on the card io */
return a = = 0xcf | | a = = 0xdf | | a = = 0xef ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:55:34 +03:00
static int zol_is_stereo ( struct zoltrix * zol )
2005-04-17 02:20:36 +04:00
{
int x1 , x2 ;
2009-03-06 19:55:34 +03:00
mutex_lock ( & zol - > lock ) ;
2006-04-08 23:06:16 +04:00
2009-03-06 19:55:34 +03:00
outb ( 0x00 , zol - > io ) ;
outb ( zol - > curvol , zol - > io ) ;
2005-04-17 02:20:36 +04:00
msleep ( 20 ) ;
2009-03-06 19:55:34 +03:00
x1 = inb ( zol - > io ) ;
2005-04-17 02:20:36 +04:00
msleep ( 10 ) ;
2009-03-06 19:55:34 +03:00
x2 = inb ( zol - > io ) ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:55:34 +03:00
mutex_unlock ( & zol - > lock ) ;
2006-04-08 23:06:16 +04:00
2009-03-06 19:55:34 +03:00
return x1 = = x2 & & x1 = = 0xcf ;
2005-04-17 02:20:36 +04:00
}
2007-04-21 01:23:38 +04:00
static int vidioc_querycap ( struct file * file , void * priv ,
struct v4l2_capability * v )
{
strlcpy ( v - > driver , " radio-zoltrix " , sizeof ( v - > driver ) ) ;
strlcpy ( v - > card , " Zoltrix Radio " , sizeof ( v - > card ) ) ;
2009-03-06 19:55:34 +03:00
strlcpy ( v - > bus_info , " ISA " , sizeof ( v - > bus_info ) ) ;
v - > capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO ;
2007-04-21 01:23:38 +04:00
return 0 ;
}
static int vidioc_g_tuner ( struct file * file , void * priv ,
struct v4l2_tuner * v )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:55:34 +03:00
struct zoltrix * zol = video_drvdata ( file ) ;
2005-04-17 02:20:36 +04:00
2007-04-21 01:23:38 +04:00
if ( v - > index > 0 )
return - EINVAL ;
2006-08-08 16:10:04 +04:00
2009-03-06 19:55:34 +03:00
strlcpy ( v - > name , " FM " , sizeof ( v - > name ) ) ;
2007-04-21 01:23:38 +04:00
v - > type = V4L2_TUNER_RADIO ;
2009-03-06 19:55:34 +03:00
v - > rangelow = 88 * 16000 ;
v - > rangehigh = 108 * 16000 ;
v - > rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO ;
2007-04-21 01:23:38 +04:00
v - > capability = V4L2_TUNER_CAP_LOW ;
if ( zol_is_stereo ( zol ) )
v - > audmode = V4L2_TUNER_MODE_STEREO ;
else
v - > audmode = V4L2_TUNER_MODE_MONO ;
2009-03-06 19:55:34 +03:00
v - > signal = 0xFFFF * zol_getsigstr ( zol ) ;
2007-04-21 01:23:38 +04:00
return 0 ;
}
2006-08-08 16:10:04 +04:00
2007-04-21 01:23:38 +04:00
static int vidioc_s_tuner ( struct file * file , void * priv ,
struct v4l2_tuner * v )
{
2009-03-06 19:55:34 +03:00
return v - > index ? - EINVAL : 0 ;
2007-04-21 01:23:38 +04:00
}
2006-08-08 16:10:04 +04:00
2007-04-21 01:23:38 +04:00
static int vidioc_s_frequency ( struct file * file , void * priv ,
struct v4l2_frequency * f )
{
2009-03-06 19:55:34 +03:00
struct zoltrix * zol = video_drvdata ( file ) ;
2006-08-08 16:10:04 +04:00
2009-11-27 10:33:25 +03:00
if ( f - > tuner ! = 0 | | f - > type ! = V4L2_TUNER_RADIO )
return - EINVAL ;
2009-03-06 19:55:34 +03:00
if ( zol_setfreq ( zol , f - > frequency ) ! = 0 )
2008-10-09 20:46:59 +04:00
return - EINVAL ;
2007-04-21 01:23:38 +04:00
return 0 ;
}
2006-08-08 16:10:04 +04:00
2007-04-21 01:23:38 +04:00
static int vidioc_g_frequency ( struct file * file , void * priv ,
struct v4l2_frequency * f )
{
2009-03-06 19:55:34 +03:00
struct zoltrix * zol = video_drvdata ( file ) ;
2007-04-21 01:23:38 +04:00
2009-11-27 10:33:25 +03:00
if ( f - > tuner ! = 0 )
return - EINVAL ;
2007-04-21 01:23:38 +04:00
f - > type = V4L2_TUNER_RADIO ;
f - > frequency = zol - > curfreq ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2007-04-21 01:23:38 +04:00
static int vidioc_queryctrl ( struct file * file , void * priv ,
struct v4l2_queryctrl * qc )
{
2009-03-06 19:55:34 +03:00
switch ( qc - > id ) {
case V4L2_CID_AUDIO_MUTE :
return v4l2_ctrl_query_fill ( qc , 0 , 1 , 1 , 1 ) ;
case V4L2_CID_AUDIO_VOLUME :
return v4l2_ctrl_query_fill ( qc , 0 , 65535 , 4096 , 65535 ) ;
2007-04-21 01:23:38 +04:00
}
return - EINVAL ;
}
static int vidioc_g_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
{
2009-03-06 19:55:34 +03:00
struct zoltrix * zol = video_drvdata ( file ) ;
2007-04-21 01:23:38 +04:00
switch ( ctrl - > id ) {
case V4L2_CID_AUDIO_MUTE :
ctrl - > value = zol - > muted ;
return 0 ;
case V4L2_CID_AUDIO_VOLUME :
ctrl - > value = zol - > curvol * 4096 ;
return 0 ;
}
return - EINVAL ;
}
static int vidioc_s_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
{
2009-03-06 19:55:34 +03:00
struct zoltrix * zol = video_drvdata ( file ) ;
2007-04-21 01:23:38 +04:00
switch ( ctrl - > id ) {
case V4L2_CID_AUDIO_MUTE :
if ( ctrl - > value )
zol_mute ( zol ) ;
else {
zol_unmute ( zol ) ;
2009-03-06 19:55:34 +03:00
zol_setvol ( zol , zol - > curvol ) ;
2006-08-08 16:10:04 +04:00
}
2007-04-21 01:23:38 +04:00
return 0 ;
case V4L2_CID_AUDIO_VOLUME :
2009-03-06 19:55:34 +03:00
zol_setvol ( zol , ctrl - > value / 4096 ) ;
2007-04-21 01:23:38 +04:00
return 0 ;
}
zol - > stereo = 1 ;
2009-03-06 19:55:34 +03:00
if ( zol_setfreq ( zol , zol - > curfreq ) ! = 0 )
2008-10-09 20:46:59 +04:00
return - EINVAL ;
2006-08-08 16:10:04 +04:00
#if 0
/* FIXME: Implement stereo/mono switch on V4L2 */
2009-03-06 19:55:34 +03:00
if ( v - > mode & VIDEO_SOUND_STEREO ) {
zol - > stereo = 1 ;
zol_setfreq ( zol , zol - > curfreq ) ;
}
if ( v - > mode & VIDEO_SOUND_MONO ) {
zol - > stereo = 0 ;
zol_setfreq ( zol , zol - > curfreq ) ;
}
2006-08-08 16:10:04 +04:00
# endif
2007-04-21 01:23:38 +04:00
return - EINVAL ;
}
2006-08-08 16:10:04 +04:00
2007-04-21 01:23:38 +04:00
static int vidioc_g_input ( struct file * filp , void * priv , unsigned int * i )
{
* i = 0 ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-04-21 01:23:38 +04:00
static int vidioc_s_input ( struct file * filp , void * priv , unsigned int i )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:55:34 +03:00
return i ? - EINVAL : 0 ;
2007-04-21 01:23:38 +04:00
}
2009-03-06 19:55:34 +03:00
static int vidioc_g_audio ( struct file * file , void * priv ,
2007-04-21 01:23:38 +04:00
struct v4l2_audio * a )
{
2009-03-06 19:55:34 +03:00
a - > index = 0 ;
strlcpy ( a - > name , " Radio " , sizeof ( a - > name ) ) ;
a - > capability = V4L2_AUDCAP_STEREO ;
2007-04-21 01:23:38 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:55:34 +03:00
static int vidioc_s_audio ( struct file * file , void * priv ,
struct v4l2_audio * a )
{
return a - > index ? - EINVAL : 0 ;
}
2005-04-17 02:20:36 +04:00
2008-12-30 12:58:20 +03:00
static const struct v4l2_file_operations zoltrix_fops =
2005-04-17 02:20:36 +04:00
{
. owner = THIS_MODULE ,
2010-11-14 15:36:23 +03:00
. unlocked_ioctl = video_ioctl2 ,
2005-04-17 02:20:36 +04:00
} ;
2008-07-21 09:57:38 +04:00
static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
2007-04-21 01:23:38 +04:00
. vidioc_querycap = vidioc_querycap ,
. vidioc_g_tuner = vidioc_g_tuner ,
. vidioc_s_tuner = vidioc_s_tuner ,
. vidioc_g_audio = vidioc_g_audio ,
. vidioc_s_audio = vidioc_s_audio ,
. vidioc_g_input = vidioc_g_input ,
. vidioc_s_input = vidioc_s_input ,
. 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 __init zoltrix_init ( void )
{
2009-03-06 19:55:34 +03:00
struct zoltrix * zol = & zoltrix_card ;
struct v4l2_device * v4l2_dev = & zol - > v4l2_dev ;
int res ;
strlcpy ( v4l2_dev - > name , " zoltrix " , sizeof ( v4l2_dev - > name ) ) ;
zol - > io = io ;
if ( zol - > io = = - 1 ) {
2009-03-09 14:11:21 +03:00
v4l2_err ( v4l2_dev , " You must set an I/O address with io=0x20c or 0x30c \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2009-03-06 19:55:34 +03:00
if ( zol - > io ! = 0x20c & & zol - > io ! = 0x30c ) {
v4l2_err ( v4l2_dev , " invalid port, try 0x20c or 0x30c \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENXIO ;
}
2009-03-06 19:55:34 +03:00
if ( ! request_region ( zol - > io , 2 , " zoltrix " ) ) {
v4l2_err ( v4l2_dev , " port 0x%x already in use \n " , zol - > io ) ;
2005-04-17 02:20:36 +04:00
return - EBUSY ;
}
2009-03-06 19:55:34 +03:00
res = v4l2_device_register ( NULL , v4l2_dev ) ;
if ( res < 0 ) {
release_region ( zol - > io , 2 ) ;
v4l2_err ( v4l2_dev , " Could not register v4l2_device \n " ) ;
return res ;
}
mutex_init ( & zol - > lock ) ;
2006-04-08 23:06:16 +04:00
2005-04-17 02:20:36 +04:00
/* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
2009-03-06 19:55:34 +03:00
outb ( 0 , zol - > io ) ;
outb ( 0 , zol - > io ) ;
2005-04-17 02:20:36 +04:00
msleep ( 20 ) ;
2009-03-06 19:55:34 +03:00
inb ( zol - > io + 3 ) ;
2005-04-17 02:20:36 +04:00
2009-03-06 19:55:34 +03:00
zol - > curvol = 0 ;
zol - > stereo = 1 ;
2005-04-17 02:20:36 +04:00
2010-11-14 15:36:23 +03:00
strlcpy ( zol - > vdev . name , v4l2_dev - > name , sizeof ( zol - > vdev . name ) ) ;
zol - > vdev . v4l2_dev = v4l2_dev ;
zol - > vdev . fops = & zoltrix_fops ;
zol - > vdev . ioctl_ops = & zoltrix_ioctl_ops ;
zol - > vdev . release = video_device_release_empty ;
video_set_drvdata ( & zol - > vdev , zol ) ;
if ( video_register_device ( & zol - > vdev , VFL_TYPE_RADIO , radio_nr ) < 0 ) {
v4l2_device_unregister ( v4l2_dev ) ;
release_region ( zol - > io , 2 ) ;
return - EINVAL ;
}
v4l2_info ( v4l2_dev , " Zoltrix Radio Plus card driver. \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-03-06 19:55:34 +03:00
static void __exit zoltrix_exit ( void )
2005-04-17 02:20:36 +04:00
{
2009-03-06 19:55:34 +03:00
struct zoltrix * zol = & zoltrix_card ;
video_unregister_device ( & zol - > vdev ) ;
v4l2_device_unregister ( & zol - > v4l2_dev ) ;
release_region ( zol - > io , 2 ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( zoltrix_init ) ;
2009-03-06 19:55:34 +03:00
module_exit ( zoltrix_exit ) ;
2005-04-17 02:20:36 +04:00