1/********************************************************************* 2 * 3 * Filename: actisys.c 4 * Version: 1.1 5 * Description: Implementation for the ACTiSYS IR-220L and IR-220L+ 6 * dongles 7 * Status: Beta. 8 * Authors: Dag Brattli <dagb@cs.uit.no> (initially) 9 * Jean Tourrilhes <jt@hpl.hp.com> (new version) 10 * Martin Diehl <mad@mdiehl.de> (new version for sir_dev) 11 * Created at: Wed Oct 21 20:02:35 1998 12 * Modified at: Sun Oct 27 22:02:13 2002 13 * Modified by: Martin Diehl <mad@mdiehl.de> 14 * 15 * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. 16 * Copyright (c) 1999 Jean Tourrilhes 17 * Copyright (c) 2002 Martin Diehl 18 * 19 * This program is free software; you can redistribute it and/or 20 * modify it under the terms of the GNU General Public License as 21 * published by the Free Software Foundation; either version 2 of 22 * the License, or (at your option) any later version. 23 * 24 * Neither Dag Brattli nor University of Tromsø admit liability nor 25 * provide warranty for any of this software. This material is 26 * provided "AS-IS" and at no charge. 27 * 28 ********************************************************************/ 29 30/* 31 * Changelog 32 * 33 * 0.8 -> 0.9999 - Jean 34 * o New initialisation procedure : much safer and correct 35 * o New procedure the change speed : much faster and simpler 36 * o Other cleanups & comments 37 * Thanks to Lichen Wang @ Actisys for his excellent help... 38 * 39 * 1.0 -> 1.1 - Martin Diehl 40 * modified for new sir infrastructure 41 */ 42 43#include <linux/module.h> 44#include <linux/delay.h> 45#include <linux/init.h> 46 47#include <net/irda/irda.h> 48 49#include "sir-dev.h" 50 51/* 52 * Define the timing of the pulses we send to the dongle (to reset it, and 53 * to toggle speeds). Basically, the limit here is the propagation speed of 54 * the signals through the serial port, the dongle being much faster. Any 55 * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can 56 * go through cleanly . If you are on the wild side, you can try to lower 57 * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!) 58 */ 59#define MIN_DELAY 10 /* 10 us to be on the conservative side */ 60 61static int actisys_open(struct sir_dev *); 62static int actisys_close(struct sir_dev *); 63static int actisys_change_speed(struct sir_dev *, unsigned); 64static int actisys_reset(struct sir_dev *); 65 66/* These are the baudrates supported, in the order available */ 67/* Note : the 220L doesn't support 38400, but we will fix that below */ 68static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 }; 69 70#define MAX_SPEEDS ARRAY_SIZE(baud_rates) 71 72static struct dongle_driver act220l = { 73 .owner = THIS_MODULE, 74 .driver_name = "Actisys ACT-220L", 75 .type = IRDA_ACTISYS_DONGLE, 76 .open = actisys_open, 77 .close = actisys_close, 78 .reset = actisys_reset, 79 .set_speed = actisys_change_speed, 80}; 81 82static struct dongle_driver act220l_plus = { 83 .owner = THIS_MODULE, 84 .driver_name = "Actisys ACT-220L+", 85 .type = IRDA_ACTISYS_PLUS_DONGLE, 86 .open = actisys_open, 87 .close = actisys_close, 88 .reset = actisys_reset, 89 .set_speed = actisys_change_speed, 90}; 91 92static int __init actisys_sir_init(void) 93{ 94 int ret; 95 96 /* First, register an Actisys 220L dongle */ 97 ret = irda_register_dongle(&act220l); 98 if (ret < 0) 99 return ret; 100 101 /* Now, register an Actisys 220L+ dongle */ 102 ret = irda_register_dongle(&act220l_plus); 103 if (ret < 0) { 104 irda_unregister_dongle(&act220l); 105 return ret; 106 } 107 return 0; 108} 109 110static void __exit actisys_sir_cleanup(void) 111{ 112 /* We have to remove both dongles */ 113 irda_unregister_dongle(&act220l_plus); 114 irda_unregister_dongle(&act220l); 115} 116 117static int actisys_open(struct sir_dev *dev) 118{ 119 struct qos_info *qos = &dev->qos; 120 121 sirdev_set_dtr_rts(dev, TRUE, TRUE); 122 123 /* Set the speeds we can accept */ 124 qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; 125 126 /* Remove support for 38400 if this is not a 220L+ dongle */ 127 if (dev->dongle_drv->type == IRDA_ACTISYS_DONGLE) 128 qos->baud_rate.bits &= ~IR_38400; 129 130 qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ 131 irda_qos_bits_to_value(qos); 132 133 /* irda thread waits 50 msec for power settling */ 134 135 return 0; 136} 137 138static int actisys_close(struct sir_dev *dev) 139{ 140 /* Power off the dongle */ 141 sirdev_set_dtr_rts(dev, FALSE, FALSE); 142 143 return 0; 144} 145 146/* 147 * Function actisys_change_speed (task) 148 * 149 * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. 150 * To cycle through the available baud rates, pulse RTS low for a few us. 151 * 152 * First, we reset the dongle to always start from a known state. 153 * Then, we cycle through the speeds by pulsing RTS low and then up. 154 * The dongle allow us to pulse quite fast, se we can set speed in one go, 155 * which is must faster ( < 100 us) and less complex than what is found 156 * in some other dongle drivers... 157 * Note that even if the new speed is the same as the current speed, 158 * we reassert the speed. This make sure that things are all right, 159 * and it's fast anyway... 160 * By the way, this function will work for both type of dongles, 161 * because the additional speed is at the end of the sequence... 162 */ 163static int actisys_change_speed(struct sir_dev *dev, unsigned speed) 164{ 165 int ret = 0; 166 int i = 0; 167 168 pr_debug("%s(), speed=%d (was %d)\n", __func__, speed, dev->speed); 169 170 /* dongle was already resetted from irda_request state machine, 171 * we are in known state (dongle default) 172 */ 173 174 /* 175 * Now, we can set the speed requested. Send RTS pulses until we 176 * reach the target speed 177 */ 178 for (i = 0; i < MAX_SPEEDS; i++) { 179 if (speed == baud_rates[i]) { 180 dev->speed = speed; 181 break; 182 } 183 /* Set RTS low for 10 us */ 184 sirdev_set_dtr_rts(dev, TRUE, FALSE); 185 udelay(MIN_DELAY); 186 187 /* Set RTS high for 10 us */ 188 sirdev_set_dtr_rts(dev, TRUE, TRUE); 189 udelay(MIN_DELAY); 190 } 191 192 /* Check if life is sweet... */ 193 if (i >= MAX_SPEEDS) { 194 actisys_reset(dev); 195 ret = -EINVAL; /* This should not happen */ 196 } 197 198 /* Basta lavoro, on se casse d'ici... */ 199 return ret; 200} 201 202/* 203 * Function actisys_reset (task) 204 * 205 * Reset the Actisys type dongle. Warning, this function must only be 206 * called with a process context! 207 * 208 * We need to do two things in this function : 209 * o first make sure that the dongle is in a state where it can operate 210 * o second put the dongle in a know state 211 * 212 * The dongle is powered of the RTS and DTR lines. In the dongle, there 213 * is a big capacitor to accommodate the current spikes. This capacitor 214 * takes a least 50 ms to be charged. In theory, the Bios set those lines 215 * up, so by the time we arrive here we should be set. It doesn't hurt 216 * to be on the conservative side, so we will wait... 217 * <Martin : move above comment to irda_config_fsm> 218 * Then, we set the speed to 9600 b/s to get in a known state (see in 219 * change_speed for details). It is needed because the IrDA stack 220 * has tried to set the speed immediately after our first return, 221 * so before we can be sure the dongle is up and running. 222 */ 223 224static int actisys_reset(struct sir_dev *dev) 225{ 226 /* Reset the dongle : set DTR low for 10 us */ 227 sirdev_set_dtr_rts(dev, FALSE, TRUE); 228 udelay(MIN_DELAY); 229 230 /* Go back to normal mode */ 231 sirdev_set_dtr_rts(dev, TRUE, TRUE); 232 233 dev->speed = 9600; /* That's the default */ 234 235 return 0; 236} 237 238MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>"); 239MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver"); 240MODULE_LICENSE("GPL"); 241MODULE_ALIAS("irda-dongle-2"); /* IRDA_ACTISYS_DONGLE */ 242MODULE_ALIAS("irda-dongle-3"); /* IRDA_ACTISYS_PLUS_DONGLE */ 243 244module_init(actisys_sir_init); 245module_exit(actisys_sir_cleanup); 246