1 /*********************************************************************
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.
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>
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>
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))
79 /* for ( i=0; (io[i] < 2000) && (i < 4); i++) { */
80 /* int ioaddr = io[i]; */
81 /* if (check_region(ioaddr, IO_EXTENT)) */
83 /* if (irport_open( i, io[i], io2[i], irq[i], dma[i]) == 0) */
91 * Function pc87108_cleanup ()
93 * Close all configured chips
97 static void irport_cleanup(void)
101 DEBUG( 4, __FUNCTION__
"()\n");
103 /* for ( i=0; i < 4; i++) { */
104 /* if ( dev_self[i]) */
105 /* irport_close( &(dev_self[i]->idev)); */
111 * Function irport_open (void)
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
);
131 * Function irport_cleanup ()
136 void irport_close( int iobase
)
138 DEBUG( 0, __FUNCTION__
"()\n");
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 */
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
;
195 DEBUG( 4, __FUNCTION__
"(), irq %d\n", irq
);
198 printk( KERN_WARNING __FUNCTION__
199 "() irq %d for unknown device.\n", irq
);
203 idev
->netdev
.interrupt
= 1;
205 iobase
= idev
->io
.iobase2
;
207 iir
= inb(iobase
+ UART_IIR
);
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 */
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
)
276 /* Tx FIFO should be empty! */
277 if (!(inb( iobase
+UART_LSR
) & UART_LSR_THRE
)) {
278 DEBUG( 0, __FUNCTION__
"(), failed, fifo not empty!\n");
282 /* Fill FIFO with current frame */
283 while (( fifo_size
-- > 0) && (actual
< len
)) {
284 /* Transmit next byte */
285 outb( buf
[actual
], iobase
+UART_TX
);
290 DEBUG( 4, __FUNCTION__
"(), fifo_size %d ; %d sent of %d\n",
291 fifo_size
, actual
, len
);
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
;
309 DEBUG( 4, __FUNCTION__
"()\n");
311 ASSERT( dev
!= NULL
, return -1;);
314 DEBUG( 4, __FUNCTION__
"(), tbusy==TRUE\n");
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
)
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
;
346 * Function irport_receive (void)
348 * Receive one frame from the infrared port
351 static void irport_receive( struct irda_device
*idev
)
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
370 async_unwrap_char( idev
, inb( iobase
+UART_RX
));
372 } while ( inb( iobase
+UART_LSR
) & UART_LSR_DR
);
378 * Function cleanup_module (void)
383 void cleanup_module(void)
389 * Function init_module (void)
393 int init_module(void)
395 if (irport_init() < 0) {