Linux 2.2.0
[davej-history.git] / drivers / net / irda / irport.c
blobae8bcb27ba7c2ebdea9651efc70e76e9c740dd6f
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>
14 * Copyright (c) 1997,1998 Dag Brattli <dagb@cs.uit.no>
15 * All Rights Reserved.
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.
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.
26 * NOTICE:
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.
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)
43 ********************************************************************/
45 #include <linux/module.h>
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>
58 #include <linux/skbuff.h>
59 #include <linux/serial_reg.h>
61 #include <net/irda/irda.h>
62 #include <net/irda/irmod.h>
63 #include <net/irda/wrapper.h>
64 #include <net/irda/irport.h>
66 #define IO_EXTENT 8
68 static unsigned int io[] = { 0x3e8, ~0, ~0, ~0 };
69 static unsigned int irq[] = { 11, 0, 0, 0 };
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);
75 __initfunc(int irport_init(void))
77 /* int i; */
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;
91 * Function pc87108_cleanup ()
93 * Close all configured chips
96 #ifdef MODULE
97 static void irport_cleanup(void)
99 int i;
101 DEBUG( 4, __FUNCTION__ "()\n");
103 /* for ( i=0; i < 4; i++) { */
104 /* if ( dev_self[i]) */
105 /* irport_close( &(dev_self[i]->idev)); */
106 /* } */
108 #endif /* MODULE */
111 * Function irport_open (void)
113 * Start IO port
116 int irport_open( int iobase)
118 DEBUG( 0, __FUNCTION__ "(), iobase=%#x\n", iobase);
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);
124 /* Turn on interrups */
125 outb(( UART_IER_THRI |UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER);
127 return 0;
131 * Function irport_cleanup ()
133 * Stop IO port
136 void irport_close( int iobase)
138 DEBUG( 0, __FUNCTION__ "()\n");
140 /* Reset UART */
141 outb( 0, iobase+UART_MCR);
143 /* Turn off interrupts */
144 outb( 0, iobase+UART_IER);
148 * Function irport_change_speed (idev, speed)
150 * Set speed of port to specified baudrate
153 void irport_change_speed( int iobase, int speed)
155 int fcr; /* FIFO control reg */
156 int lcr; /* Line control reg */
157 int divisor;
159 DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
161 DEBUG( 0, __FUNCTION__ "(), iobase=%#x\n", iobase);
163 /* Turn off interrupts */
164 outb( 0, iobase+UART_IER);
166 divisor = SPEED_MAX/speed;
168 fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
170 /* IrDA ports use 8N1 */
171 lcr = UART_LCR_WLEN8;
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 */
179 /* Turn on interrups */
180 outb( UART_IER_THRI|UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER);
184 * Function irport_interrupt (irq, dev_id, regs)
188 void irport_interrupt( int irq, void *dev_id, struct pt_regs *regs)
190 struct irda_device *idev = (struct irda_device *) dev_id;
192 int iobase, status;
193 int iir;
195 DEBUG( 4, __FUNCTION__ "(), irq %d\n", irq);
197 if ( !idev) {
198 printk( KERN_WARNING __FUNCTION__
199 "() irq %d for unknown device.\n", irq);
200 return;
203 idev->netdev.interrupt = 1;
205 iobase = idev->io.iobase2;
207 iir = inb(iobase + UART_IIR);
208 do {
209 status = inb( iobase+UART_LSR);
211 if (status & UART_LSR_DR) {
212 /* Receive interrupt */
213 irport_receive(idev);
215 if (status & UART_LSR_THRE) {
216 /* Transmitter ready for data */
217 irport_write_wakeup(idev);
219 } while (!(inb(iobase+UART_IIR) & UART_IIR_NO_INT));
221 idev->netdev.interrupt = 0;
225 * Function irport_write_wakeup (tty)
227 * Called by the driver when there's room for more data. If we have
228 * more packets to send, we send them here.
231 static void irport_write_wakeup( struct irda_device *idev)
233 int actual = 0, count;
235 DEBUG( 4, __FUNCTION__ "() <%ld>\n", jiffies);
237 ASSERT( idev != NULL, return;);
238 ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
240 /* Finished with frame? */
241 if ( idev->tx_buff.offset == idev->tx_buff.len) {
244 * Now serial buffer is almost free & we can start
245 * transmission of another packet
247 DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
249 idev->netdev.tbusy = 0; /* Unlock */
250 idev->stats.tx_packets++;
252 /* Schedule network layer, so we can get some more frames */
253 mark_bh( NET_BH);
255 return;
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;
267 * Function irport_write (driver)
272 static int irport_write( int iobase, int fifo_size, __u8 *buf, int len)
274 int actual = 0;
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;
282 /* Fill FIFO with current frame */
283 while (( fifo_size-- > 0) && (actual < len)) {
284 /* Transmit next byte */
285 outb( buf[actual], iobase+UART_TX);
287 actual++;
290 DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n",
291 fifo_size, actual, len);
293 return actual;
297 * Function irport_xmit (void)
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.
303 int irport_hard_xmit( struct sk_buff *skb, struct device *dev)
305 struct irda_device *idev;
306 int xbofs;
307 int actual;
309 DEBUG( 4, __FUNCTION__ "()\n");
311 ASSERT( dev != NULL, return -1;);
313 if ( dev->tbusy) {
314 DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n");
316 return -EBUSY;
319 idev = (struct irda_device *) dev->priv;
321 ASSERT( idev != NULL, return -1;);
322 ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
324 /* Lock transmit buffer */
325 if ( irda_lock( (void *) &dev->tbusy) == FALSE)
326 return -EBUSY;
329 * Transfer skb to tx_buff while wrapping, stuffing and making CRC
331 idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data,
332 idev->tx_buff.truesize);
334 actual = irport_write( idev->io.iobase2, idev->io.fifo_size,
335 idev->tx_buff.data, idev->tx_buff.len);
337 idev->tx_buff.offset = actual;
338 idev->tx_buff.head = idev->tx_buff.data + actual;
340 dev_kfree_skb( skb);
342 return 0;
346 * Function irport_receive (void)
348 * Receive one frame from the infrared port
351 static void irport_receive( struct irda_device *idev)
353 int iobase;
355 if ( !idev)
356 return;
358 DEBUG( 4, __FUNCTION__ "()\n");
360 iobase = idev->io.iobase2;
362 if ( idev->rx_buff.len == 0)
363 idev->rx_buff.head = idev->rx_buff.data;
366 * Receive all characters in Rx FIFO, unwrap and unstuff them.
367 * async_unwrap_char will deliver all found frames
369 do {
370 async_unwrap_char( idev, inb( iobase+UART_RX));
372 } while ( inb( iobase+UART_LSR) & UART_LSR_DR);
375 #ifdef MODULE
378 * Function cleanup_module (void)
383 void cleanup_module(void)
385 irport_cleanup();
389 * Function init_module (void)
393 int init_module(void)
395 if (irport_init() < 0) {
396 cleanup_module();
397 return 1;
399 return(0);
402 #endif /* MODULE */