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

Linux Cross Reference
Linux/drivers/net/irda/irport.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:      irport.c
  4  * Version:       0.8
  5  * Description:   Serial driver for IrDA. 
  6  * Status:        Experimental.
  7  * Author:        Dag Brattli <dagb@cs.uit.no>
  8  * Created at:    Sun Aug  3 13:49:59 1997
  9  * Modified at:   Sat May 23 23:15:20 1998
 10  * Modified by:   Dag Brattli <dagb@cs.uit.no>
 11  * Sources:       serial.c by Linus Torvalds 
 12  *                serial_serial.c by Aage Kvalnes <aage@cs.uit.no>
 13  * 
 14  *     Copyright (c) 1997,1998 Dag Brattli <dagb@cs.uit.no>
 15  *     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  *     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  *     NOTICE:
 27  *
 28  *     This driver is ment to be a small serial driver to be used for
 29  *     IR-chipsets that has a UART (16550) compatibility mode. If your
 30  *     chipset is is UART only, you should probably use IrTTY instead since
 31  *     the Linux serial driver is probably more robust and optimized.
 32  *
 33  *     The functions in this file may be used by FIR drivers, but this
 34  *     driver knows nothing about FIR drivers so don't ever insert such
 35  *     code into this file. Instead you should code your FIR driver in a
 36  *     separate file, and then call the functions in this file if
 37  *     necessary. This is becase it is difficult to use the Linux serial
 38  *     driver with a FIR driver becase they must share interrupts etc. Most
 39  *     FIR chipsets can function in advanced SIR mode, and you should
 40  *     probably use that mode instead of the UART compatibility mode (and
 41  *     then just forget about this file)
 42  *
 43  ********************************************************************/
 44 
 45 #include <linux/module.h>
 46 
 47 #include <linux/kernel.h>
 48 #include <linux/types.h>
 49 #include <linux/ioport.h>
 50 #include <linux/malloc.h>
 51 #include <linux/string.h>
 52 #include <asm/system.h>
 53 #include <asm/bitops.h>
 54 #include <asm/io.h>
 55 #include <linux/errno.h>
 56 #include <linux/init.h>
 57 
 58 #include <linux/skbuff.h>
 59 #include <linux/serial_reg.h>
 60 
 61 #include <net/irda/irda.h>
 62 #include <net/irda/irmod.h>
 63 #include <net/irda/wrapper.h>
 64 #include <net/irda/irport.h>
 65 
 66 #define IO_EXTENT 8
 67 
 68 static unsigned int io[]  = { 0x3e8, ~0, ~0, ~0 };
 69 static unsigned int irq[] = { 11, 0, 0, 0 };
 70 
 71 static void irport_write_wakeup( struct irda_device *idev);
 72 static int  irport_write( int iobase, int fifo_size, __u8 *buf, int len);
 73 static void irport_receive( struct irda_device *idev);
 74 
 75 __initfunc(int irport_init(void))
 76 {
 77 /*      int i; */
 78 
 79 /*      for ( i=0; (io[i] < 2000) && (i < 4); i++) { */
 80 /*              int ioaddr = io[i]; */
 81 /*              if (check_region(ioaddr, IO_EXTENT)) */
 82 /*                      continue; */
 83 /*              if (irport_open( i, io[i], io2[i], irq[i], dma[i]) == 0) */
 84 /*                      return 0; */
 85 /*      } */
 86 /*      return -ENODEV; */
 87         return 0;
 88 }
 89 
 90 /*
 91  * Function pc87108_cleanup ()
 92  *
 93  *    Close all configured chips
 94  *
 95  */
 96 #ifdef MODULE
 97 static void irport_cleanup(void)
 98 {
 99 /*      int i; */
100 
101         DEBUG( 4, __FUNCTION__ "()\n");
102 
103         /* for ( i=0; i < 4; i++) { */
104 /*              if ( dev_self[i]) */
105 /*                      irport_close( &(dev_self[i]->idev)); */
106 /*      } */
107 }
108 #endif /* MODULE */
109 
110 /*
111  * Function irport_open (void)
112  *
113  *    Start IO port 
114  *
115  */
116 int irport_open( int iobase)
117 {
118         DEBUG( 0, __FUNCTION__ "(), iobase=%#x\n", iobase);
119 
120         /* Initialize UART */
121         outb( UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
122         outb(( UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
123         
124         /* Turn on interrups */
125         outb(( UART_IER_THRI |UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER); 
126         
127         return 0;
128 }
129 
130 /*
131  * Function irport_cleanup ()
132  *
133  *    Stop IO port
134  *
135  */
136 void irport_close( int iobase) 
137 {
138         DEBUG( 0, __FUNCTION__ "()\n");
139 
140         /* Reset UART */
141         outb( 0, iobase+UART_MCR);
142 
143         /* Turn off interrupts */
144         outb( 0, iobase+UART_IER); 
145 }
146 
147 /*
148  * Function irport_change_speed (idev, speed)
149  *
150  *    Set speed of port to specified baudrate
151  *
152  */
153 void irport_change_speed( int iobase, int speed) 
154 {
155         int fcr;    /* FIFO control reg */
156         int lcr;    /* Line control reg */
157         int divisor;
158 
159         DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
160 
161         DEBUG( 0, __FUNCTION__ "(), iobase=%#x\n", iobase);
162 
163         /* Turn off interrupts */
164         outb( 0, iobase+UART_IER); 
165 
166         divisor = SPEED_MAX/speed;
167         
168         fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
169         
170         /* IrDA ports use 8N1 */
171         lcr = UART_LCR_WLEN8;
172         
173         outb( UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
174         outb( divisor & 0xff,      iobase+UART_DLL); /* Set speed */
175         outb( divisor >> 8,        iobase+UART_DLM);
176         outb( lcr,                 iobase+UART_LCR); /* Set 8N1 */
177         outb( fcr,                 iobase+UART_FCR); /* Enable FIFO's */
178 
179         /* Turn on interrups */
180         outb( UART_IER_THRI|UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); 
181 }
182 
183 /*
184  * Function irport_interrupt (irq, dev_id, regs)
185  *
186  *    
187  */
188 void irport_interrupt( int irq, void *dev_id, struct pt_regs *regs) 
189 {
190         struct irda_device *idev = (struct irda_device *) dev_id;
191 
192         int iobase, status;
193         int iir;
194 
195         DEBUG( 4, __FUNCTION__ "(), irq %d\n", irq);
196 
197         if ( !idev) {
198                 printk( KERN_WARNING __FUNCTION__ 
199                         "() irq %d for unknown device.\n", irq);
200                 return;
201         }
202 
203         idev->netdev.interrupt = 1;
204 
205         iobase = idev->io.iobase2;
206 
207         iir = inb(iobase + UART_IIR);
208         do {
209                 status = inb( iobase+UART_LSR);
210                 
211                 if (status & UART_LSR_DR) {
212                         /* Receive interrupt */
213                         irport_receive(idev);
214                 }
215                 if (status & UART_LSR_THRE) {
216                         /* Transmitter ready for data */
217                         irport_write_wakeup(idev);
218                 }
219         } while (!(inb(iobase+UART_IIR) & UART_IIR_NO_INT));
220 
221         idev->netdev.interrupt = 0;
222 }
223 
224 /*
225  * Function irport_write_wakeup (tty)
226  *
227  *    Called by the driver when there's room for more data.  If we have
228  *    more packets to send, we send them here.
229  *
230  */
231 static void irport_write_wakeup( struct irda_device *idev)
232 {
233         int actual = 0, count;
234         
235         DEBUG( 4, __FUNCTION__ "() <%ld>\n", jiffies);
236         
237         ASSERT( idev != NULL, return;);
238         ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
239 
240         /* Finished with frame?  */
241         if ( idev->tx_buff.offset == idev->tx_buff.len)  {
242 
243                 /* 
244                  *  Now serial buffer is almost free & we can start 
245                  *  transmission of another packet 
246                  */
247                 DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
248 
249                 idev->netdev.tbusy = 0; /* Unlock */
250                 idev->stats.tx_packets++;
251 
252                 /* Schedule network layer, so we can get some more frames */
253                 mark_bh( NET_BH);
254 
255                 return;
256         }
257 
258         /* Write data left in transmit buffer */
259         count = idev->tx_buff.len - idev->tx_buff.offset;
260         actual = irport_write( idev->io.iobase2, idev->io.fifo_size, 
261                                idev->tx_buff.head, count);
262         idev->tx_buff.offset += actual;
263         idev->tx_buff.head += actual;
264 }
265 
266 /*
267  * Function irport_write (driver)
268  *
269  *    
270  *
271  */
272 static int irport_write( int iobase, int fifo_size, __u8 *buf, int len)
273 {
274         int actual = 0;
275 
276         /* Tx FIFO should be empty! */
277         if (!(inb( iobase+UART_LSR) & UART_LSR_THRE)) {
278                 DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
279                 return -1;
280         }
281         
282         /* Fill FIFO with current frame */
283         while (( fifo_size-- > 0) && (actual < len)) {
284                 /* Transmit next byte */
285                 outb( buf[actual], iobase+UART_TX);
286 
287                 actual++;
288         }
289         
290         DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
291                fifo_size, actual, len);
292 
293         return actual;
294 }
295 
296 /*
297  * Function irport_xmit (void)
298  *
299  *    Transmits the current frame until FIFO is full, then
300  *    waits until the next transmitt interrupt, and continues until the
301  *    frame is transmited.
302  */
303 int irport_hard_xmit( struct sk_buff *skb, struct device *dev)
304 {
305         struct irda_device *idev;
306         int actual;
307 
308         DEBUG( 4, __FUNCTION__ "()\n");
309 
310         ASSERT( dev != NULL, return -1;);
311 
312         if ( dev->tbusy) {
313                 DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n");
314                 
315                 return -EBUSY;
316         }
317         
318         idev = (struct irda_device *) dev->priv;
319 
320         ASSERT( idev != NULL, return -1;);
321         ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
322 
323         /* Lock transmit buffer */
324         if ( irda_lock( (void *) &dev->tbusy) == FALSE)
325                 return -EBUSY;
326         
327         /*  
328          *  Transfer skb to tx_buff while wrapping, stuffing and making CRC 
329          */
330         idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, 
331                                             idev->tx_buff.truesize);
332         
333         actual = irport_write( idev->io.iobase2, idev->io.fifo_size, 
334                                idev->tx_buff.data, idev->tx_buff.len);
335         
336         idev->tx_buff.offset = actual;
337         idev->tx_buff.head = idev->tx_buff.data + actual;
338         
339         dev_kfree_skb( skb);
340         
341         return 0;
342 }
343         
344 /*
345  * Function irport_receive (void)
346  *
347  *    Receive one frame from the infrared port
348  *
349  */
350 static void irport_receive( struct irda_device *idev) 
351 {
352         int iobase;
353 
354         if ( !idev)
355                 return;
356 
357         DEBUG( 4, __FUNCTION__ "()\n");
358 
359         iobase = idev->io.iobase2;
360 
361         if ( idev->rx_buff.len == 0)
362                 idev->rx_buff.head = idev->rx_buff.data;
363         
364         /*  
365          * Receive all characters in Rx FIFO, unwrap and unstuff them. 
366          * async_unwrap_char will deliver all found frames  
367          */
368         do {
369                 async_unwrap_char( idev, inb( iobase+UART_RX));
370                 
371         } while ( inb( iobase+UART_LSR) & UART_LSR_DR); 
372 }
373 
374 #ifdef MODULE
375 
376 /*
377  * Function cleanup_module (void)
378  *
379  *    
380  *
381  */
382 void cleanup_module(void)
383 {
384         irport_cleanup();
385 }
386 
387 /*
388  * Function init_module (void)
389  *
390  *    
391  */
392 int init_module(void)
393 {
394         if (irport_init() < 0) {
395                 cleanup_module();
396                 return 1;
397         }
398         return(0);
399 }
400 
401 #endif /* MODULE */
402 
403 

~ [ 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.