1/********************************************************************* 2 * 3 * Filename: girbil.c 4 * Version: 1.2 5 * Description: Implementation for the Greenwich GIrBIL dongle 6 * Status: Experimental. 7 * Author: Dag Brattli <dagb@cs.uit.no> 8 * Created at: Sat Feb 6 21:02:33 1999 9 * Modified at: Fri Dec 17 09:13:20 1999 10 * Modified by: Dag Brattli <dagb@cs.uit.no> 11 * 12 * Copyright (c) 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/init.h> 28 29#include <net/irda/irda.h> 30 31#include "sir-dev.h" 32 33static int girbil_reset(struct sir_dev *dev); 34static int girbil_open(struct sir_dev *dev); 35static int girbil_close(struct sir_dev *dev); 36static int girbil_change_speed(struct sir_dev *dev, unsigned speed); 37 38/* Control register 1 */ 39#define GIRBIL_TXEN 0x01 /* Enable transmitter */ 40#define GIRBIL_RXEN 0x02 /* Enable receiver */ 41#define GIRBIL_ECAN 0x04 /* Cancel self emitted data */ 42#define GIRBIL_ECHO 0x08 /* Echo control characters */ 43 44/* LED Current Register (0x2) */ 45#define GIRBIL_HIGH 0x20 46#define GIRBIL_MEDIUM 0x21 47#define GIRBIL_LOW 0x22 48 49/* Baud register (0x3) */ 50#define GIRBIL_2400 0x30 51#define GIRBIL_4800 0x31 52#define GIRBIL_9600 0x32 53#define GIRBIL_19200 0x33 54#define GIRBIL_38400 0x34 55#define GIRBIL_57600 0x35 56#define GIRBIL_115200 0x36 57 58/* Mode register (0x4) */ 59#define GIRBIL_IRDA 0x40 60#define GIRBIL_ASK 0x41 61 62/* Control register 2 (0x5) */ 63#define GIRBIL_LOAD 0x51 /* Load the new baud rate value */ 64 65static struct dongle_driver girbil = { 66 .owner = THIS_MODULE, 67 .driver_name = "Greenwich GIrBIL", 68 .type = IRDA_GIRBIL_DONGLE, 69 .open = girbil_open, 70 .close = girbil_close, 71 .reset = girbil_reset, 72 .set_speed = girbil_change_speed, 73}; 74 75static int __init girbil_sir_init(void) 76{ 77 return irda_register_dongle(&girbil); 78} 79 80static void __exit girbil_sir_cleanup(void) 81{ 82 irda_unregister_dongle(&girbil); 83} 84 85static int girbil_open(struct sir_dev *dev) 86{ 87 struct qos_info *qos = &dev->qos; 88 89 /* Power on dongle */ 90 sirdev_set_dtr_rts(dev, TRUE, TRUE); 91 92 qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; 93 qos->min_turn_time.bits = 0x03; 94 irda_qos_bits_to_value(qos); 95 96 /* irda thread waits 50 msec for power settling */ 97 98 return 0; 99} 100 101static int girbil_close(struct sir_dev *dev) 102{ 103 /* Power off dongle */ 104 sirdev_set_dtr_rts(dev, FALSE, FALSE); 105 106 return 0; 107} 108 109/* 110 * Function girbil_change_speed (dev, speed) 111 * 112 * Set the speed for the Girbil type dongle. 113 * 114 */ 115 116#define GIRBIL_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) 117 118static int girbil_change_speed(struct sir_dev *dev, unsigned speed) 119{ 120 unsigned state = dev->fsm.substate; 121 unsigned delay = 0; 122 u8 control[2]; 123 static int ret = 0; 124 125 /* dongle alread reset - port and dongle at default speed */ 126 127 switch(state) { 128 129 case SIRDEV_STATE_DONGLE_SPEED: 130 131 /* Set DTR and Clear RTS to enter command mode */ 132 sirdev_set_dtr_rts(dev, FALSE, TRUE); 133 134 udelay(25); /* better wait a little while */ 135 136 ret = 0; 137 switch (speed) { 138 default: 139 ret = -EINVAL; 140 /* fall through */ 141 case 9600: 142 control[0] = GIRBIL_9600; 143 break; 144 case 19200: 145 control[0] = GIRBIL_19200; 146 break; 147 case 34800: 148 control[0] = GIRBIL_38400; 149 break; 150 case 57600: 151 control[0] = GIRBIL_57600; 152 break; 153 case 115200: 154 control[0] = GIRBIL_115200; 155 break; 156 } 157 control[1] = GIRBIL_LOAD; 158 159 /* Write control bytes */ 160 sirdev_raw_write(dev, control, 2); 161 162 dev->speed = speed; 163 164 state = GIRBIL_STATE_WAIT_SPEED; 165 delay = 100; 166 break; 167 168 case GIRBIL_STATE_WAIT_SPEED: 169 /* Go back to normal mode */ 170 sirdev_set_dtr_rts(dev, TRUE, TRUE); 171 172 udelay(25); /* better wait a little while */ 173 break; 174 175 default: 176 net_err_ratelimited("%s - undefined state %d\n", 177 __func__, state); 178 ret = -EINVAL; 179 break; 180 } 181 dev->fsm.substate = state; 182 return (delay > 0) ? delay : ret; 183} 184 185/* 186 * Function girbil_reset (driver) 187 * 188 * This function resets the girbil dongle. 189 * 190 * Algorithm: 191 * 0. set RTS, and wait at least 5 ms 192 * 1. clear RTS 193 */ 194 195 196#define GIRBIL_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET + 1) 197#define GIRBIL_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET + 2) 198#define GIRBIL_STATE_WAIT3_RESET (SIRDEV_STATE_DONGLE_RESET + 3) 199 200static int girbil_reset(struct sir_dev *dev) 201{ 202 unsigned state = dev->fsm.substate; 203 unsigned delay = 0; 204 u8 control = GIRBIL_TXEN | GIRBIL_RXEN; 205 int ret = 0; 206 207 switch (state) { 208 case SIRDEV_STATE_DONGLE_RESET: 209 /* Reset dongle */ 210 sirdev_set_dtr_rts(dev, TRUE, FALSE); 211 /* Sleep at least 5 ms */ 212 delay = 20; 213 state = GIRBIL_STATE_WAIT1_RESET; 214 break; 215 216 case GIRBIL_STATE_WAIT1_RESET: 217 /* Set DTR and clear RTS to enter command mode */ 218 sirdev_set_dtr_rts(dev, FALSE, TRUE); 219 delay = 20; 220 state = GIRBIL_STATE_WAIT2_RESET; 221 break; 222 223 case GIRBIL_STATE_WAIT2_RESET: 224 /* Write control byte */ 225 sirdev_raw_write(dev, &control, 1); 226 delay = 20; 227 state = GIRBIL_STATE_WAIT3_RESET; 228 break; 229 230 case GIRBIL_STATE_WAIT3_RESET: 231 /* Go back to normal mode */ 232 sirdev_set_dtr_rts(dev, TRUE, TRUE); 233 dev->speed = 9600; 234 break; 235 236 default: 237 net_err_ratelimited("%s(), undefined state %d\n", 238 __func__, state); 239 ret = -1; 240 break; 241 } 242 dev->fsm.substate = state; 243 return (delay > 0) ? delay : ret; 244} 245 246MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); 247MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver"); 248MODULE_LICENSE("GPL"); 249MODULE_ALIAS("irda-dongle-4"); /* IRDA_GIRBIL_DONGLE */ 250 251module_init(girbil_sir_init); 252module_exit(girbil_sir_cleanup); 253