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/sched.h>
29 #include <linux/init.h>
30
31 #include <net/irda/irda.h>
32 #include <net/irda/irmod.h>
33 #include <net/irda/irda_device.h>
34 #include <net/irda/irtty.h>
35
36 static void tekram_open(dongle_t *self, struct qos_info *qos);
37 static void tekram_close(dongle_t *self);
38 static int tekram_change_speed(struct irda_task *task);
39 static int tekram_reset(struct irda_task *task);
40
41 #define TEKRAM_115200 0x00
42 #define TEKRAM_57600 0x01
43 #define TEKRAM_38400 0x02
44 #define TEKRAM_19200 0x03
45 #define TEKRAM_9600 0x04
46
47 #define TEKRAM_PW 0x10 /* Pulse select bit */
48
49 static struct dongle_reg dongle = {
50 Q_NULL,
51 IRDA_TEKRAM_DONGLE,
52 tekram_open,
53 tekram_close,
54 tekram_reset,
55 tekram_change_speed,
56 };
57
tekram_init(void)58 int __init tekram_init(void)
59 {
60 return irda_device_register_dongle(&dongle);
61 }
62
tekram_cleanup(void)63 void tekram_cleanup(void)
64 {
65 irda_device_unregister_dongle(&dongle);
66 }
67
tekram_open(dongle_t * self,struct qos_info * qos)68 static void tekram_open(dongle_t *self, struct qos_info *qos)
69 {
70 IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
71
72 qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
73 qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
74 irda_qos_bits_to_value(qos);
75
76 MOD_INC_USE_COUNT;
77 }
78
tekram_close(dongle_t * self)79 static void tekram_close(dongle_t *self)
80 {
81 IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
82
83 /* Power off dongle */
84 self->set_dtr_rts(self->dev, FALSE, FALSE);
85
86 if (self->reset_task)
87 irda_task_delete(self->reset_task);
88 if (self->speed_task)
89 irda_task_delete(self->speed_task);
90
91 MOD_DEC_USE_COUNT;
92 }
93
94 /*
95 * Function tekram_change_speed (dev, state, speed)
96 *
97 * Set the speed for the Tekram IRMate 210 type dongle. Warning, this
98 * function must be called with a process context!
99 *
100 * Algorithm
101 * 1. clear DTR
102 * 2. set RTS, and wait at least 7 us
103 * 3. send Control Byte to the IR-210 through TXD to set new baud rate
104 * wait until the stop bit of Control Byte is sent (for 9600 baud rate,
105 * it takes about 100 msec)
106 * 5. clear RTS (return to NORMAL Operation)
107 * 6. wait at least 50 us, new setting (baud rate, etc) takes effect here
108 * after
109 */
tekram_change_speed(struct irda_task * task)110 static int tekram_change_speed(struct irda_task *task)
111 {
112 dongle_t *self = (dongle_t *) task->instance;
113 __u32 speed = (__u32) task->param;
114 __u8 byte;
115 int ret = 0;
116
117 IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
118
119 ASSERT(task != NULL, return -1;);
120
121 if (self->speed_task && self->speed_task != task) {
122 IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
123 return MSECS_TO_JIFFIES(10);
124 } else
125 self->speed_task = task;
126
127 switch (speed) {
128 default:
129 case 9600:
130 byte = TEKRAM_PW|TEKRAM_9600;
131 break;
132 case 19200:
133 byte = TEKRAM_PW|TEKRAM_19200;
134 break;
135 case 38400:
136 byte = TEKRAM_PW|TEKRAM_38400;
137 break;
138 case 57600:
139 byte = TEKRAM_PW|TEKRAM_57600;
140 break;
141 case 115200:
142 byte = TEKRAM_115200;
143 break;
144 }
145
146 switch (task->state) {
147 case IRDA_TASK_INIT:
148 case IRDA_TASK_CHILD_INIT:
149 /*
150 * Need to reset the dongle and go to 9600 bps before
151 * programming
152 */
153 if (irda_task_execute(self, tekram_reset, NULL, task,
154 (void *) speed))
155 {
156 /* Dongle need more time to reset */
157 irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
158
159 /* Give reset 1 sec to finish */
160 ret = MSECS_TO_JIFFIES(1000);
161 } else
162 irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
163 break;
164 case IRDA_TASK_CHILD_WAIT:
165 WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
166 ret = -1;
167 break;
168 case IRDA_TASK_CHILD_DONE:
169 /* Set DTR, Clear RTS */
170 self->set_dtr_rts(self->dev, TRUE, FALSE);
171
172 /* Wait at least 7us */
173 udelay(14);
174
175 /* Write control byte */
176 self->write(self->dev, &byte, 1);
177
178 irda_task_next_state(task, IRDA_TASK_WAIT);
179
180 /* Wait at least 100 ms */
181 ret = MSECS_TO_JIFFIES(150);
182 break;
183 case IRDA_TASK_WAIT:
184 /* Set DTR, Set RTS */
185 self->set_dtr_rts(self->dev, TRUE, TRUE);
186
187 irda_task_next_state(task, IRDA_TASK_DONE);
188 self->speed_task = NULL;
189 break;
190 default:
191 ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
192 irda_task_next_state(task, IRDA_TASK_DONE);
193 self->speed_task = NULL;
194 ret = -1;
195 break;
196 }
197 return ret;
198 }
199
200 /*
201 * Function tekram_reset (driver)
202 *
203 * This function resets the tekram dongle. Warning, this function
204 * must be called with a process context!!
205 *
206 * Algorithm:
207 * 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 )
208 * 1. clear RTS
209 * 2. set DTR, and wait at least 1 ms
210 * 3. clear DTR to SPACE state, wait at least 50 us for further
211 * operation
212 */
tekram_reset(struct irda_task * task)213 int tekram_reset(struct irda_task *task)
214 {
215 dongle_t *self = (dongle_t *) task->instance;
216 int ret = 0;
217
218 IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
219
220 ASSERT(task != NULL, return -1;);
221
222 if (self->reset_task && self->reset_task != task) {
223 IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
224 return MSECS_TO_JIFFIES(10);
225 } else
226 self->reset_task = task;
227
228 /* Power off dongle */
229 //self->set_dtr_rts(self->dev, FALSE, FALSE);
230 self->set_dtr_rts(self->dev, TRUE, TRUE);
231
232 switch (task->state) {
233 case IRDA_TASK_INIT:
234 irda_task_next_state(task, IRDA_TASK_WAIT1);
235
236 /* Sleep 50 ms */
237 ret = MSECS_TO_JIFFIES(50);
238 break;
239 case IRDA_TASK_WAIT1:
240 /* Clear DTR, Set RTS */
241 self->set_dtr_rts(self->dev, FALSE, TRUE);
242
243 irda_task_next_state(task, IRDA_TASK_WAIT2);
244
245 /* Should sleep 1 ms */
246 ret = MSECS_TO_JIFFIES(1);
247 break;
248 case IRDA_TASK_WAIT2:
249 /* Set DTR, Set RTS */
250 self->set_dtr_rts(self->dev, TRUE, TRUE);
251
252 /* Wait at least 50 us */
253 udelay(75);
254
255 irda_task_next_state(task, IRDA_TASK_DONE);
256 self->reset_task = NULL;
257 break;
258 default:
259 ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
260 irda_task_next_state(task, IRDA_TASK_DONE);
261 self->reset_task = NULL;
262 ret = -1;
263 }
264 return ret;
265 }
266
267 #ifdef MODULE
268 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
269 MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver");
270 MODULE_LICENSE("GPL");
271
272 /*
273 * Function init_module (void)
274 *
275 * Initialize Tekram module
276 *
277 */
init_module(void)278 int init_module(void)
279 {
280 return tekram_init();
281 }
282
283 /*
284 * Function cleanup_module (void)
285 *
286 * Cleanup Tekram module
287 *
288 */
cleanup_module(void)289 void cleanup_module(void)
290 {
291 tekram_cleanup();
292 }
293 #endif /* MODULE */
294