diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/irda/ma600.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/net/irda/ma600.c')
-rw-r--r-- | drivers/net/irda/ma600.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/drivers/net/irda/ma600.c b/drivers/net/irda/ma600.c new file mode 100644 index 000000000000..f5e6836667fd --- /dev/null +++ b/drivers/net/irda/ma600.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: ma600.c | ||
4 | * Version: 0.1 | ||
5 | * Description: Implementation of the MA600 dongle | ||
6 | * Status: Experimental. | ||
7 | * Author: Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95 | ||
8 | * Created at: Sat Jun 10 20:02:35 2000 | ||
9 | * Modified at: | ||
10 | * Modified by: | ||
11 | * | ||
12 | * Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing | ||
13 | * information on the MA600 dongle | ||
14 | * | ||
15 | * Copyright (c) 2000 Leung, All Rights Reserved. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License as | ||
19 | * published by the Free Software Foundation; either version 2 of | ||
20 | * the License, or (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * GNU General Public License for more details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License | ||
28 | * along with this program; if not, write to the Free Software | ||
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
30 | * MA 02111-1307 USA | ||
31 | * | ||
32 | ********************************************************************/ | ||
33 | |||
34 | /* define this macro for release version */ | ||
35 | //#define NDEBUG | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/tty.h> | ||
40 | #include <linux/init.h> | ||
41 | |||
42 | #include <net/irda/irda.h> | ||
43 | #include <net/irda/irda_device.h> | ||
44 | |||
45 | #ifndef NDEBUG | ||
46 | #undef IRDA_DEBUG | ||
47 | #define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args)) | ||
48 | |||
49 | #undef ASSERT | ||
50 | #define ASSERT(expr, func) \ | ||
51 | if(!(expr)) { \ | ||
52 | printk( "Assertion failed! %s,%s,%s,line=%d\n",\ | ||
53 | #expr,__FILE__,__FUNCTION__,__LINE__); \ | ||
54 | func} | ||
55 | #endif | ||
56 | |||
57 | /* convert hex value to ascii hex */ | ||
58 | static const char hexTbl[] = "0123456789ABCDEF"; | ||
59 | |||
60 | |||
61 | static void ma600_open(dongle_t *self, struct qos_info *qos); | ||
62 | static void ma600_close(dongle_t *self); | ||
63 | static int ma600_change_speed(struct irda_task *task); | ||
64 | static int ma600_reset(struct irda_task *task); | ||
65 | |||
66 | /* control byte for MA600 */ | ||
67 | #define MA600_9600 0x00 | ||
68 | #define MA600_19200 0x01 | ||
69 | #define MA600_38400 0x02 | ||
70 | #define MA600_57600 0x03 | ||
71 | #define MA600_115200 0x04 | ||
72 | #define MA600_DEV_ID1 0x05 | ||
73 | #define MA600_DEV_ID2 0x06 | ||
74 | #define MA600_2400 0x08 | ||
75 | |||
76 | static struct dongle_reg dongle = { | ||
77 | .type = IRDA_MA600_DONGLE, | ||
78 | .open = ma600_open, | ||
79 | .close = ma600_close, | ||
80 | .reset = ma600_reset, | ||
81 | .change_speed = ma600_change_speed, | ||
82 | .owner = THIS_MODULE, | ||
83 | }; | ||
84 | |||
85 | static int __init ma600_init(void) | ||
86 | { | ||
87 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
88 | return irda_device_register_dongle(&dongle); | ||
89 | } | ||
90 | |||
91 | static void __exit ma600_cleanup(void) | ||
92 | { | ||
93 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
94 | irda_device_unregister_dongle(&dongle); | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | Power on: | ||
99 | (0) Clear RTS and DTR for 1 second | ||
100 | (1) Set RTS and DTR for 1 second | ||
101 | (2) 9600 bps now | ||
102 | Note: assume RTS, DTR are clear before | ||
103 | */ | ||
104 | static void ma600_open(dongle_t *self, struct qos_info *qos) | ||
105 | { | ||
106 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
107 | |||
108 | qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400 | ||
109 | |IR_57600|IR_115200; | ||
110 | qos->min_turn_time.bits = 0x01; /* Needs at least 1 ms */ | ||
111 | irda_qos_bits_to_value(qos); | ||
112 | |||
113 | //self->set_dtr_rts(self->dev, FALSE, FALSE); | ||
114 | // should wait 1 second | ||
115 | |||
116 | self->set_dtr_rts(self->dev, TRUE, TRUE); | ||
117 | // should wait 1 second | ||
118 | } | ||
119 | |||
120 | static void ma600_close(dongle_t *self) | ||
121 | { | ||
122 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
123 | |||
124 | /* Power off dongle */ | ||
125 | self->set_dtr_rts(self->dev, FALSE, FALSE); | ||
126 | } | ||
127 | |||
128 | static __u8 get_control_byte(__u32 speed) | ||
129 | { | ||
130 | __u8 byte; | ||
131 | |||
132 | switch (speed) { | ||
133 | default: | ||
134 | case 115200: | ||
135 | byte = MA600_115200; | ||
136 | break; | ||
137 | case 57600: | ||
138 | byte = MA600_57600; | ||
139 | break; | ||
140 | case 38400: | ||
141 | byte = MA600_38400; | ||
142 | break; | ||
143 | case 19200: | ||
144 | byte = MA600_19200; | ||
145 | break; | ||
146 | case 9600: | ||
147 | byte = MA600_9600; | ||
148 | break; | ||
149 | case 2400: | ||
150 | byte = MA600_2400; | ||
151 | break; | ||
152 | } | ||
153 | |||
154 | return byte; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Function ma600_change_speed (dev, state, speed) | ||
159 | * | ||
160 | * Set the speed for the MA600 type dongle. Warning, this | ||
161 | * function must be called with a process context! | ||
162 | * | ||
163 | * Algorithm | ||
164 | * 1. Reset | ||
165 | * 2. clear RTS, set DTR and wait for 1ms | ||
166 | * 3. send Control Byte to the MA600 through TXD to set new baud rate | ||
167 | * wait until the stop bit of Control Byte is sent (for 9600 baud rate, | ||
168 | * it takes about 10 msec) | ||
169 | * 4. set RTS, set DTR (return to NORMAL Operation) | ||
170 | * 5. wait at least 10 ms, new setting (baud rate, etc) takes effect here | ||
171 | * after | ||
172 | */ | ||
173 | static int ma600_change_speed(struct irda_task *task) | ||
174 | { | ||
175 | dongle_t *self = (dongle_t *) task->instance; | ||
176 | __u32 speed = (__u32) task->param; | ||
177 | static __u8 byte; | ||
178 | __u8 byte_echo; | ||
179 | int ret = 0; | ||
180 | |||
181 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
182 | |||
183 | ASSERT(task != NULL, return -1;); | ||
184 | |||
185 | if (self->speed_task && self->speed_task != task) { | ||
186 | IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__); | ||
187 | return msecs_to_jiffies(10); | ||
188 | } else { | ||
189 | self->speed_task = task; | ||
190 | } | ||
191 | |||
192 | switch (task->state) { | ||
193 | case IRDA_TASK_INIT: | ||
194 | case IRDA_TASK_CHILD_INIT: | ||
195 | /* | ||
196 | * Need to reset the dongle and go to 9600 bps before | ||
197 | * programming | ||
198 | */ | ||
199 | if (irda_task_execute(self, ma600_reset, NULL, task, | ||
200 | (void *) speed)) { | ||
201 | /* Dongle need more time to reset */ | ||
202 | irda_task_next_state(task, IRDA_TASK_CHILD_WAIT); | ||
203 | |||
204 | /* give 1 second to finish */ | ||
205 | ret = msecs_to_jiffies(1000); | ||
206 | } else { | ||
207 | irda_task_next_state(task, IRDA_TASK_CHILD_DONE); | ||
208 | } | ||
209 | break; | ||
210 | |||
211 | case IRDA_TASK_CHILD_WAIT: | ||
212 | IRDA_WARNING("%s(), resetting dongle timed out!\n", | ||
213 | __FUNCTION__); | ||
214 | ret = -1; | ||
215 | break; | ||
216 | |||
217 | case IRDA_TASK_CHILD_DONE: | ||
218 | /* Set DTR, Clear RTS */ | ||
219 | self->set_dtr_rts(self->dev, TRUE, FALSE); | ||
220 | |||
221 | ret = msecs_to_jiffies(1); /* Sleep 1 ms */ | ||
222 | irda_task_next_state(task, IRDA_TASK_WAIT); | ||
223 | break; | ||
224 | |||
225 | case IRDA_TASK_WAIT: | ||
226 | speed = (__u32) task->param; | ||
227 | byte = get_control_byte(speed); | ||
228 | |||
229 | /* Write control byte */ | ||
230 | self->write(self->dev, &byte, sizeof(byte)); | ||
231 | |||
232 | irda_task_next_state(task, IRDA_TASK_WAIT1); | ||
233 | |||
234 | /* Wait at least 10 ms */ | ||
235 | ret = msecs_to_jiffies(15); | ||
236 | break; | ||
237 | |||
238 | case IRDA_TASK_WAIT1: | ||
239 | /* Read control byte echo */ | ||
240 | self->read(self->dev, &byte_echo, sizeof(byte_echo)); | ||
241 | |||
242 | if(byte != byte_echo) { | ||
243 | /* if control byte != echo, I don't know what to do */ | ||
244 | printk(KERN_WARNING "%s() control byte written != read!\n", __FUNCTION__); | ||
245 | printk(KERN_WARNING "control byte = 0x%c%c\n", | ||
246 | hexTbl[(byte>>4)&0x0f], hexTbl[byte&0x0f]); | ||
247 | printk(KERN_WARNING "byte echo = 0x%c%c\n", | ||
248 | hexTbl[(byte_echo>>4) & 0x0f], | ||
249 | hexTbl[byte_echo & 0x0f]); | ||
250 | #ifndef NDEBUG | ||
251 | } else { | ||
252 | IRDA_DEBUG(2, "%s() control byte write read OK\n", __FUNCTION__); | ||
253 | #endif | ||
254 | } | ||
255 | |||
256 | /* Set DTR, Set RTS */ | ||
257 | self->set_dtr_rts(self->dev, TRUE, TRUE); | ||
258 | |||
259 | irda_task_next_state(task, IRDA_TASK_WAIT2); | ||
260 | |||
261 | /* Wait at least 10 ms */ | ||
262 | ret = msecs_to_jiffies(10); | ||
263 | break; | ||
264 | |||
265 | case IRDA_TASK_WAIT2: | ||
266 | irda_task_next_state(task, IRDA_TASK_DONE); | ||
267 | self->speed_task = NULL; | ||
268 | break; | ||
269 | |||
270 | default: | ||
271 | IRDA_ERROR("%s(), unknown state %d\n", | ||
272 | __FUNCTION__, task->state); | ||
273 | irda_task_next_state(task, IRDA_TASK_DONE); | ||
274 | self->speed_task = NULL; | ||
275 | ret = -1; | ||
276 | break; | ||
277 | } | ||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Function ma600_reset (driver) | ||
283 | * | ||
284 | * This function resets the ma600 dongle. Warning, this function | ||
285 | * must be called with a process context!! | ||
286 | * | ||
287 | * Algorithm: | ||
288 | * 0. DTR=0, RTS=1 and wait 10 ms | ||
289 | * 1. DTR=1, RTS=1 and wait 10 ms | ||
290 | * 2. 9600 bps now | ||
291 | */ | ||
292 | int ma600_reset(struct irda_task *task) | ||
293 | { | ||
294 | dongle_t *self = (dongle_t *) task->instance; | ||
295 | int ret = 0; | ||
296 | |||
297 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
298 | |||
299 | ASSERT(task != NULL, return -1;); | ||
300 | |||
301 | if (self->reset_task && self->reset_task != task) { | ||
302 | IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__); | ||
303 | return msecs_to_jiffies(10); | ||
304 | } else | ||
305 | self->reset_task = task; | ||
306 | |||
307 | switch (task->state) { | ||
308 | case IRDA_TASK_INIT: | ||
309 | /* Clear DTR and Set RTS */ | ||
310 | self->set_dtr_rts(self->dev, FALSE, TRUE); | ||
311 | irda_task_next_state(task, IRDA_TASK_WAIT1); | ||
312 | ret = msecs_to_jiffies(10); /* Sleep 10 ms */ | ||
313 | break; | ||
314 | case IRDA_TASK_WAIT1: | ||
315 | /* Set DTR and RTS */ | ||
316 | self->set_dtr_rts(self->dev, TRUE, TRUE); | ||
317 | irda_task_next_state(task, IRDA_TASK_WAIT2); | ||
318 | ret = msecs_to_jiffies(10); /* Sleep 10 ms */ | ||
319 | break; | ||
320 | case IRDA_TASK_WAIT2: | ||
321 | irda_task_next_state(task, IRDA_TASK_DONE); | ||
322 | self->reset_task = NULL; | ||
323 | break; | ||
324 | default: | ||
325 | IRDA_ERROR("%s(), unknown state %d\n", | ||
326 | __FUNCTION__, task->state); | ||
327 | irda_task_next_state(task, IRDA_TASK_DONE); | ||
328 | self->reset_task = NULL; | ||
329 | ret = -1; | ||
330 | } | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95"); | ||
335 | MODULE_DESCRIPTION("MA600 dongle driver version 0.1"); | ||
336 | MODULE_LICENSE("GPL"); | ||
337 | MODULE_ALIAS("irda-dongle-11"); /* IRDA_MA600_DONGLE */ | ||
338 | |||
339 | /* | ||
340 | * Function init_module (void) | ||
341 | * | ||
342 | * Initialize MA600 module | ||
343 | * | ||
344 | */ | ||
345 | module_init(ma600_init); | ||
346 | |||
347 | /* | ||
348 | * Function cleanup_module (void) | ||
349 | * | ||
350 | * Cleanup MA600 module | ||
351 | * | ||
352 | */ | ||
353 | module_exit(ma600_cleanup); | ||
354 | |||