1/********************************************************************* 2 * 3 * Filename: tekram.c 4 * Version: 1.2 5 * Description: Implementation of the Tekram IrMate IR-210B dongle 6 * Status: Experimental. 7 * Author: Dag Brattli <dagb@cs.uit.no> 8 * Created at: Wed Oct 21 20:02:35 1998 9 * Modified at: Fri Dec 17 09:13:09 1999 10 * Modified by: Dag Brattli <dagb@cs.uit.no> 11 * 12 * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License as 16 * published by the Free Software Foundation; either version 2 of 17 * the License, or (at your option) any later version. 18 * 19 * Neither Dag Brattli nor University of Troms� admit liability nor 20 * provide warranty for any of this software. This material is 21 * provided "AS-IS" and at no charge. 22 * 23 ********************************************************************/ 24 25#include <linux/module.h> 26#include <linux/delay.h> 27#include <linux/tty.h> 28#include <linux/init.h> 29 30#include <net/irda/irda.h> 31#include <net/irda/irda_device.h> 32 33static void tekram_open(dongle_t *self, struct qos_info *qos); 34static void tekram_close(dongle_t *self); 35static int tekram_change_speed(struct irda_task *task); 36static int tekram_reset(struct irda_task *task); 37 38#define TEKRAM_115200 0x00 39#define TEKRAM_57600 0x01 40#define TEKRAM_38400 0x02 41#define TEKRAM_19200 0x03 42#define TEKRAM_9600 0x04 43 44#define TEKRAM_PW 0x10 /* Pulse select bit */ 45 46static struct dongle_reg dongle = { 47 .type = IRDA_TEKRAM_DONGLE, 48 .open = tekram_open, 49 .close = tekram_close, 50 .reset = tekram_reset, 51 .change_speed = tekram_change_speed, 52 .owner = THIS_MODULE, 53}; 54 55static int __init tekram_init(void) 56{ 57 return irda_device_register_dongle(&dongle); 58} 59 60static void __exit tekram_cleanup(void) 61{ 62 irda_device_unregister_dongle(&dongle); 63} 64 65static void tekram_open(dongle_t *self, struct qos_info *qos) 66{ 67 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); 68 69 qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; 70 qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ 71 irda_qos_bits_to_value(qos); 72} 73 74static void tekram_close(dongle_t *self) 75{ 76 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); 77 78 /* Power off dongle */ 79 self->set_dtr_rts(self->dev, FALSE, FALSE); 80 81 if (self->reset_task) 82 irda_task_delete(self->reset_task); 83 if (self->speed_task) 84 irda_task_delete(self->speed_task); 85} 86 87/* 88 * Function tekram_change_speed (dev, state, speed) 89 * 90 * Set the speed for the Tekram IRMate 210 type dongle. Warning, this 91 * function must be called with a process context! 92 * 93 * Algorithm 94 * 1. clear DTR 95 * 2. set RTS, and wait at least 7 us 96 * 3. send Control Byte to the IR-210 through TXD to set new baud rate 97 * wait until the stop bit of Control Byte is sent (for 9600 baud rate, 98 * it takes about 100 msec) 99 * 5. clear RTS (return to NORMAL Operation) 100 * 6. wait at least 50 us, new setting (baud rate, etc) takes effect here 101 * after 102 */ 103static int tekram_change_speed(struct irda_task *task) 104{ 105 dongle_t *self = (dongle_t *) task->instance; 106 __u32 speed = (__u32) task->param; 107 __u8 byte; 108 int ret = 0; 109 110 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); 111 112 IRDA_ASSERT(task != NULL, return -1;); 113 114 if (self->speed_task && self->speed_task != task) { 115 IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ ); 116 return msecs_to_jiffies(10); 117 } else 118 self->speed_task = task; 119 120 switch (speed) { 121 default: 122 case 9600: 123 byte = TEKRAM_PW|TEKRAM_9600; 124 break; 125 case 19200: 126 byte = TEKRAM_PW|TEKRAM_19200; 127 break; 128 case 38400: 129 byte = TEKRAM_PW|TEKRAM_38400; 130 break; 131 case 57600: 132 byte = TEKRAM_PW|TEKRAM_57600; 133 break; 134 case 115200: 135 byte = TEKRAM_115200; 136 break; 137 } 138 139 switch (task->state) { 140 case IRDA_TASK_INIT: 141 case IRDA_TASK_CHILD_INIT: 142 /* 143 * Need to reset the dongle and go to 9600 bps before 144 * programming 145 */ 146 if (irda_task_execute(self, tekram_reset, NULL, task, 147 (void *) speed)) 148 { 149 /* Dongle need more time to reset */ 150 irda_task_next_state(task, IRDA_TASK_CHILD_WAIT); 151 152 /* Give reset 1 sec to finish */ 153 ret = msecs_to_jiffies(1000); 154 } else 155 irda_task_next_state(task, IRDA_TASK_CHILD_DONE); 156 break; 157 case IRDA_TASK_CHILD_WAIT: 158 IRDA_WARNING("%s(), resetting dongle timed out!\n", 159 __FUNCTION__); 160 ret = -1; 161 break; 162 case IRDA_TASK_CHILD_DONE: 163 /* Set DTR, Clear RTS */ 164 self->set_dtr_rts(self->dev, TRUE, FALSE); 165 166 /* Wait at least 7us */ 167 udelay(14); 168 169 /* Write control byte */ 170 self->write(self->dev, &byte, 1); 171 172 irda_task_next_state(task, IRDA_TASK_WAIT); 173 174 /* Wait at least 100 ms */ 175 ret = msecs_to_jiffies(150); 176 break; 177 case IRDA_TASK_WAIT: 178 /* Set DTR, Set RTS */ 179 self->set_dtr_rts(self->dev, TRUE, TRUE); 180 181 irda_task_next_state(task, IRDA_TASK_DONE); 182 self->speed_task = NULL; 183 break; 184 default: 185 IRDA_ERROR("%s(), unknown state %d\n", 186 __FUNCTION__, task->state); 187 irda_task_next_state(task, IRDA_TASK_DONE); 188 self->speed_task = NULL; 189 ret = -1; 190 break; 191 } 192 return ret; 193} 194 195/* 196 * Function tekram_reset (driver) 197 * 198 * This function resets the tekram dongle. Warning, this function 199 * must be called with a process context!! 200 * 201 * Algorithm: 202 * 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 ) 203 * 1. clear RTS 204 * 2. set DTR, and wait at least 1 ms 205 * 3. clear DTR to SPACE state, wait at least 50 us for further 206 * operation 207 */ 208int tekram_reset(struct irda_task *task) 209{ 210 dongle_t *self = (dongle_t *) task->instance; 211 int ret = 0; 212 213 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); 214 215 IRDA_ASSERT(task != NULL, return -1;); 216 217 if (self->reset_task && self->reset_task != task) { 218 IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ ); 219 return msecs_to_jiffies(10); 220 } else 221 self->reset_task = task; 222 223 /* Power off dongle */ 224 //self->set_dtr_rts(self->dev, FALSE, FALSE); 225 self->set_dtr_rts(self->dev, TRUE, TRUE); 226 227 switch (task->state) { 228 case IRDA_TASK_INIT: 229 irda_task_next_state(task, IRDA_TASK_WAIT1); 230 231 /* Sleep 50 ms */ 232 ret = msecs_to_jiffies(50); 233 break; 234 case IRDA_TASK_WAIT1: 235 /* Clear DTR, Set RTS */ 236 self->set_dtr_rts(self->dev, FALSE, TRUE); 237 238 irda_task_next_state(task, IRDA_TASK_WAIT2); 239 240 /* Should sleep 1 ms */ 241 ret = msecs_to_jiffies(1); 242 break; 243 case IRDA_TASK_WAIT2: 244 /* Set DTR, Set RTS */ 245 self->set_dtr_rts(self->dev, TRUE, TRUE); 246 247 /* Wait at least 50 us */ 248 udelay(75); 249 250 irda_task_next_state(task, IRDA_TASK_DONE); 251 self->reset_task = NULL; 252 break; 253 default: 254 IRDA_ERROR("%s(), unknown state %d\n", 255 __FUNCTION__, task->state); 256 irda_task_next_state(task, IRDA_TASK_DONE); 257 self->reset_task = NULL; 258 ret = -1; 259 } 260 return ret; 261} 262 263MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); 264MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver"); 265MODULE_LICENSE("GPL"); 266MODULE_ALIAS("irda-dongle-0"); /* IRDA_TEKRAM_DONGLE */ 267 268/* 269 * Function init_module (void) 270 * 271 * Initialize Tekram module 272 * 273 */ 274module_init(tekram_init); 275 276/* 277 * Function cleanup_module (void) 278 * 279 * Cleanup Tekram module 280 * 281 */ 282module_exit(tekram_cleanup); 283