2005-04-17 02:20:36 +04:00
/*********************************************************************
*
* Filename : tekram . c
* Version : 1.3
* Description : Implementation of the Tekram IrMate IR - 210 B dongle
* Status : Experimental .
* Author : Dag Brattli < dagb @ cs . uit . no >
* Created at : Wed Oct 21 20 : 02 : 35 1998
* Modified at : Sun Oct 27 22 : 02 : 38 2002
* Modified by : Martin Diehl < mad @ mdiehl . de >
*
* Copyright ( c ) 1998 - 1999 Dag Brattli ,
* Copyright ( c ) 2002 Martin Diehl ,
* All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
*
2007-10-20 01:21:04 +04:00
* Neither Dag Brattli nor University of Tromsø admit liability nor
2005-04-17 02:20:36 +04:00
* provide warranty for any of this software . This material is
* provided " AS-IS " and at no charge .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <net/irda/irda.h>
# include "sir-dev.h"
static int tekram_delay = 150 ; /* default is 150 ms */
module_param ( tekram_delay , int , 0 ) ;
MODULE_PARM_DESC ( tekram_delay , " tekram dongle write complete delay " ) ;
static int tekram_open ( struct sir_dev * ) ;
static int tekram_close ( struct sir_dev * ) ;
static int tekram_change_speed ( struct sir_dev * , unsigned ) ;
static int tekram_reset ( struct sir_dev * ) ;
# define TEKRAM_115200 0x00
# define TEKRAM_57600 0x01
# define TEKRAM_38400 0x02
# define TEKRAM_19200 0x03
# define TEKRAM_9600 0x04
# define TEKRAM_PW 0x10 /* Pulse select bit */
static struct dongle_driver tekram = {
. owner = THIS_MODULE ,
. driver_name = " Tekram IR-210B " ,
. type = IRDA_TEKRAM_DONGLE ,
. open = tekram_open ,
. close = tekram_close ,
. reset = tekram_reset ,
. set_speed = tekram_change_speed ,
} ;
static int __init tekram_sir_init ( void )
{
if ( tekram_delay < 1 | | tekram_delay > 500 )
tekram_delay = 200 ;
IRDA_DEBUG ( 1 , " %s - using %d ms delay \n " ,
tekram . driver_name , tekram_delay ) ;
return irda_register_dongle ( & tekram ) ;
}
static void __exit tekram_sir_cleanup ( void )
{
irda_unregister_dongle ( & tekram ) ;
}
static int tekram_open ( struct sir_dev * dev )
{
struct qos_info * qos = & dev - > qos ;
2008-07-31 04:20:18 +04:00
IRDA_DEBUG ( 2 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
sirdev_set_dtr_rts ( dev , TRUE , TRUE ) ;
qos - > baud_rate . bits & = IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 ;
qos - > min_turn_time . bits = 0x01 ; /* Needs at least 10 ms */
irda_qos_bits_to_value ( qos ) ;
/* irda thread waits 50 msec for power settling */
return 0 ;
}
static int tekram_close ( struct sir_dev * dev )
{
2008-07-31 04:20:18 +04:00
IRDA_DEBUG ( 2 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Power off dongle */
sirdev_set_dtr_rts ( dev , FALSE , FALSE ) ;
return 0 ;
}
/*
* Function tekram_change_speed ( dev , state , speed )
*
* Set the speed for the Tekram IRMate 210 type dongle . Warning , this
* function must be called with a process context !
*
* Algorithm
* 1. clear DTR
* 2. set RTS , and wait at least 7 us
* 3. send Control Byte to the IR - 210 through TXD to set new baud rate
* wait until the stop bit of Control Byte is sent ( for 9600 baud rate ,
* it takes about 100 msec )
*
* [ oops , why 100 msec ? sending 1 byte ( 10 bits ) takes 1.05 msec
* - is this probably to compensate for delays in tty layer ? ]
*
* 5. clear RTS ( return to NORMAL Operation )
* 6. wait at least 50 us , new setting ( baud rate , etc ) takes effect here
* after
*/
# define TEKRAM_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1)
static int tekram_change_speed ( struct sir_dev * dev , unsigned speed )
{
unsigned state = dev - > fsm . substate ;
unsigned delay = 0 ;
u8 byte ;
static int ret = 0 ;
2008-07-31 04:20:18 +04:00
IRDA_DEBUG ( 2 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
switch ( state ) {
case SIRDEV_STATE_DONGLE_SPEED :
switch ( speed ) {
default :
speed = 9600 ;
ret = - EINVAL ;
/* fall thru */
case 9600 :
byte = TEKRAM_PW | TEKRAM_9600 ;
break ;
case 19200 :
byte = TEKRAM_PW | TEKRAM_19200 ;
break ;
case 38400 :
byte = TEKRAM_PW | TEKRAM_38400 ;
break ;
case 57600 :
byte = TEKRAM_PW | TEKRAM_57600 ;
break ;
case 115200 :
byte = TEKRAM_115200 ;
break ;
}
/* Set DTR, Clear RTS */
sirdev_set_dtr_rts ( dev , TRUE , FALSE ) ;
/* Wait at least 7us */
udelay ( 14 ) ;
/* Write control byte */
sirdev_raw_write ( dev , & byte , 1 ) ;
dev - > speed = speed ;
state = TEKRAM_STATE_WAIT_SPEED ;
delay = tekram_delay ;
break ;
case TEKRAM_STATE_WAIT_SPEED :
/* Set DTR, Set RTS */
sirdev_set_dtr_rts ( dev , TRUE , TRUE ) ;
udelay ( 50 ) ;
break ;
default :
2008-07-31 04:20:18 +04:00
IRDA_ERROR ( " %s - undefined state %d \n " , __func__ , state ) ;
2005-04-17 02:20:36 +04:00
ret = - EINVAL ;
break ;
}
dev - > fsm . substate = state ;
return ( delay > 0 ) ? delay : ret ;
}
/*
* Function tekram_reset ( driver )
*
* This function resets the tekram dongle . Warning , this function
* must be called with a process context ! !
*
* Algorithm :
* 0. Clear RTS and DTR , and wait 50 ms ( power off the IR - 210 )
* 1. clear RTS
* 2. set DTR , and wait at least 1 ms
* 3. clear DTR to SPACE state , wait at least 50 us for further
* operation
*/
static int tekram_reset ( struct sir_dev * dev )
{
2008-07-31 04:20:18 +04:00
IRDA_DEBUG ( 2 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Clear DTR, Set RTS */
sirdev_set_dtr_rts ( dev , FALSE , TRUE ) ;
/* Should sleep 1 ms */
msleep ( 1 ) ;
/* Set DTR, Set RTS */
sirdev_set_dtr_rts ( dev , TRUE , TRUE ) ;
/* Wait at least 50 us */
udelay ( 75 ) ;
dev - > speed = 9600 ;
return 0 ;
}
MODULE_AUTHOR ( " Dag Brattli <dagb@cs.uit.no> " ) ;
MODULE_DESCRIPTION ( " Tekram IrMate IR-210B dongle driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " irda-dongle-0 " ) ; /* IRDA_TEKRAM_DONGLE */
module_init ( tekram_sir_init ) ;
module_exit ( tekram_sir_cleanup ) ;