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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.