~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/net/irda/actisys.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*********************************************************************
  2  *                
  3  * Filename:      actisys.c
  4  * Version:       1.0
  5  * Description:   Implementation for the ACTiSYS IR-220L and IR-220L+ 
  6  *                dongles
  7  * Status:        Beta.
  8  * Authors:       Dag Brattli <dagb@cs.uit.no> (initially)
  9  *                Jean Tourrilhes <jt@hpl.hp.com> (new version)
 10  * Created at:    Wed Oct 21 20:02:35 1998
 11  * Modified at:   Fri Dec 17 09:10:43 1999
 12  * Modified by:   Dag Brattli <dagb@cs.uit.no>
 13  * 
 14  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
 15  *     Copyright (c) 1999 Jean Tourrilhes
 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  *     Neither Dag Brattli nor University of Tromsų admit liability nor
 23  *     provide warranty for any of this software. This material is 
 24  *     provided "AS-IS" and at no charge.
 25  *     
 26  ********************************************************************/
 27 
 28 /*
 29  * Changelog
 30  *
 31  * 0.8 -> 0.9999 - Jean
 32  *      o New initialisation procedure : much safer and correct
 33  *      o New procedure the change speed : much faster and simpler
 34  *      o Other cleanups & comments
 35  *      Thanks to Lichen Wang @ Actisys for his excellent help...
 36  */
 37 
 38 #include <linux/module.h>
 39 #include <linux/delay.h>
 40 #include <linux/tty.h>
 41 #include <linux/sched.h>
 42 #include <linux/init.h>
 43 
 44 #include <net/irda/irda.h>
 45 #include <net/irda/irmod.h>
 46 #include <net/irda/irda_device.h>
 47 
 48 /* 
 49  * Define the timing of the pulses we send to the dongle (to reset it, and
 50  * to toggle speeds). Basically, the limit here is the propagation speed of
 51  * the signals through the serial port, the dongle being much faster.  Any
 52  * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can
 53  * go through cleanly . If you are on the wild side, you can try to lower
 54  * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!)
 55  */
 56 #define MIN_DELAY 10    /* 10 us to be on the conservative side */
 57 
 58 static int  actisys_change_speed(struct irda_task *task);
 59 static int  actisys_reset(struct irda_task *task);
 60 static void actisys_open(dongle_t *self, struct qos_info *qos);
 61 static void actisys_close(dongle_t *self);
 62 
 63 /* These are the baudrates supported, in the order available */
 64 /* Note : the 220L doesn't support 38400, but we will fix that below */
 65 static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
 66 #define MAX_SPEEDS 5
 67 
 68 static struct dongle_reg dongle = {
 69         Q_NULL,
 70         IRDA_ACTISYS_DONGLE,
 71         actisys_open,
 72         actisys_close,
 73         actisys_reset,
 74         actisys_change_speed,
 75 };
 76 
 77 static struct dongle_reg dongle_plus = {
 78         Q_NULL,
 79         IRDA_ACTISYS_PLUS_DONGLE,
 80         actisys_open,
 81         actisys_close,
 82         actisys_reset,
 83         actisys_change_speed,
 84 };
 85 
 86 /*
 87  * Function actisys_change_speed (task)
 88  *
 89  *      There is two model of Actisys dongle we are dealing with,
 90  * the 220L and 220L+. At this point, only irattach knows with
 91  * kind the user has requested (it was an argument on irattach
 92  * command line).
 93  *      So, we register a dongle of each sort and let irattach
 94  * pick the right one...
 95  */
 96 int __init actisys_init(void)
 97 {
 98         int ret;
 99 
100         /* First, register an Actisys 220L dongle */
101         ret = irda_device_register_dongle(&dongle);
102         if (ret < 0)
103                 return ret;
104         /* Now, register an Actisys 220L+ dongle */
105         ret = irda_device_register_dongle(&dongle_plus);
106         if (ret < 0) {
107                 irda_device_unregister_dongle(&dongle);
108                 return ret;
109         }       
110         return 0;
111 }
112 
113 void actisys_cleanup(void)
114 {
115         /* We have to remove both dongles */
116         irda_device_unregister_dongle(&dongle);
117         irda_device_unregister_dongle(&dongle_plus);
118 }
119 
120 static void actisys_open(dongle_t *self, struct qos_info *qos)
121 {
122         /* Power on the dongle */
123         self->set_dtr_rts(self->dev, TRUE, TRUE);
124 
125         /* Set the speeds we can accept */
126         qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
127 
128         /* Remove support for 38400 if this is not a 220L+ dongle */
129         if (self->issue->type == IRDA_ACTISYS_DONGLE)
130                 qos->baud_rate.bits &= ~IR_38400;
131         
132         qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
133 
134         MOD_INC_USE_COUNT;
135 }
136 
137 static void actisys_close(dongle_t *self)
138 {
139         /* Power off the dongle */
140         self->set_dtr_rts(self->dev, FALSE, FALSE);
141 
142         MOD_DEC_USE_COUNT;
143 }
144 
145 /*
146  * Function actisys_change_speed (task)
147  *
148  *    Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles.
149  *    To cycle through the available baud rates, pulse RTS low for a few us.
150  *
151  *      First, we reset the dongle to always start from a known state.
152  *      Then, we cycle through the speeds by pulsing RTS low and then up.
153  *      The dongle allow us to pulse quite fast, se we can set speed in one go,
154  * which is must faster ( < 100 us) and less complex than what is found
155  * in some other dongle drivers...
156  *      Note that even if the new speed is the same as the current speed,
157  * we reassert the speed. This make sure that things are all right,
158  * and it's fast anyway...
159  *      By the way, this function will work for both type of dongles,
160  * because the additional speed is at the end of the sequence...
161  */
162 static int actisys_change_speed(struct irda_task *task)
163 {
164         dongle_t *self = (dongle_t *) task->instance;
165         __u32 speed = (__u32) task->param;      /* Target speed */
166         int ret = 0;
167         int i = 0;
168 
169         IRDA_DEBUG(4, __FUNCTION__ "(), speed=%d (was %d)\n", speed, 
170                    self->speed);
171 
172         /* Go to a known state by reseting the dongle */
173 
174         /* Reset the dongle : set DTR low for 10 us */
175         self->set_dtr_rts(self->dev, FALSE, TRUE);
176         udelay(MIN_DELAY);
177 
178         /* Go back to normal mode (we are now at 9600 b/s) */
179         self->set_dtr_rts(self->dev, TRUE, TRUE);
180  
181         /* 
182          * Now, we can set the speed requested. Send RTS pulses until we
183          * reach the target speed 
184          */
185         for (i=0; i<MAX_SPEEDS; i++) {
186                 if (speed == baud_rates[i]) {
187                         self->speed = baud_rates[i];
188                         break;
189                 }
190                 /* Make sure previous pulse is finished */
191                 udelay(MIN_DELAY);
192 
193                 /* Set RTS low for 10 us */
194                 self->set_dtr_rts(self->dev, TRUE, FALSE);
195                 udelay(MIN_DELAY);
196 
197                 /* Set RTS high for 10 us */
198                 self->set_dtr_rts(self->dev, TRUE, TRUE);
199         }
200 
201         /* Check if life is sweet... */
202         if (i >= MAX_SPEEDS)
203                 ret = -1;  /* This should not happen */
204 
205         /* Basta lavoro, on se casse d'ici... */
206         irda_task_next_state(task, IRDA_TASK_DONE);
207 
208         return ret;
209 }
210 
211 /*
212  * Function actisys_reset (task)
213  *
214  *      Reset the Actisys type dongle. Warning, this function must only be
215  *      called with a process context!
216  *
217  * We need to do two things in this function :
218  *      o first make sure that the dongle is in a state where it can operate
219  *      o second put the dongle in a know state
220  *
221  *      The dongle is powered of the RTS and DTR lines. In the dongle, there
222  * is a big capacitor to accomodate the current spikes. This capacitor
223  * takes a least 50 ms to be charged. In theory, the Bios set those lines
224  * up, so by the time we arrive here we should be set. It doesn't hurt
225  * to be on the conservative side, so we will wait...
226  *      Then, we set the speed to 9600 b/s to get in a known state (see in
227  * change_speed for details). It is needed because the IrDA stack
228  * has tried to set the speed immediately after our first return,
229  * so before we can be sure the dongle is up and running.
230  */
231 static int actisys_reset(struct irda_task *task)
232 {
233         dongle_t *self = (dongle_t *) task->instance;
234         int ret = 0;
235 
236         ASSERT(task != NULL, return -1;);
237 
238         self->reset_task = task;
239 
240         switch (task->state) {
241         case IRDA_TASK_INIT:
242                 /* Set both DTR & RTS to power up the dongle */
243                 /* In theory redundant with power up in actisys_open() */
244                 self->set_dtr_rts(self->dev, TRUE, TRUE);
245                 
246                 /* Sleep 50 ms to make sure capacitor is charged */
247                 ret = MSECS_TO_JIFFIES(50);
248                 irda_task_next_state(task, IRDA_TASK_WAIT);
249                 break;
250         case IRDA_TASK_WAIT:                    
251                 /* Reset the dongle : set DTR low for 10 us */
252                 self->set_dtr_rts(self->dev, FALSE, TRUE);
253                 udelay(MIN_DELAY);
254 
255                 /* Go back to normal mode */
256                 self->set_dtr_rts(self->dev, TRUE, TRUE);
257         
258                 irda_task_next_state(task, IRDA_TASK_DONE);
259                 self->reset_task = NULL;
260                 self->speed = 9600;     /* That's the default */
261                 break;
262         default:
263                 ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
264                 irda_task_next_state(task, IRDA_TASK_DONE);
265                 self->reset_task = NULL;
266                 ret = -1;
267                 break;
268         }
269         return ret;
270 }
271 
272 #ifdef MODULE
273 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>");
274 MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver");       
275                 
276 /*
277  * Function init_module (void)
278  *
279  *    Initialize Actisys module
280  *
281  */
282 int init_module(void)
283 {
284         return actisys_init();
285 }
286 
287 /*
288  * Function cleanup_module (void)
289  *
290  *    Cleanup Actisys module
291  *
292  */
293 void cleanup_module(void)
294 {
295         actisys_cleanup();
296 }
297 #endif /* MODULE */
298 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.