Merge master.kernel.org:/pub/scm/linux/kernel/git/sridhar/lksctp-2.6
[linux-2.6] / drivers / net / irda / ma600.c
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