| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /***************************************************************** | 
 | 2 |  * | 
 | 3 |  * Filename:		donauboe.c | 
 | 4 |  * Version: 		2.17 | 
 | 5 |  * Description:   Driver for the Toshiba OBOE (or type-O or 701) | 
 | 6 |  *                FIR Chipset, also supports the DONAUOBOE (type-DO | 
 | 7 |  *                or d01) FIR chipset which as far as I know is | 
 | 8 |  *                register compatible. | 
 | 9 |  * Documentation: http://libxg.free.fr/irda/lib-irda.html | 
 | 10 |  * Status:        Experimental. | 
 | 11 |  * Author:        James McKenzie <james@fishsoup.dhs.org> | 
 | 12 |  * Created at:    Sat May 8  12:35:27 1999 | 
 | 13 |  * Modified:      Paul Bristow <paul.bristow@technologist.com> | 
 | 14 |  * Modified:      Mon Nov 11 19:10:05 1999 | 
 | 15 |  * Modified:      James McKenzie <james@fishsoup.dhs.org> | 
 | 16 |  * Modified:      Thu Mar 16 12:49:00 2000 (Substantial rewrite) | 
 | 17 |  * Modified:      Sat Apr 29 00:23:03 2000 (Added DONAUOBOE support) | 
 | 18 |  * Modified:      Wed May 24 23:45:02 2000 (Fixed chipio_t structure) | 
 | 19 |  * Modified: 2.13 Christian Gennerat <christian.gennerat@polytechnique.org> | 
 | 20 |  * Modified: 2.13 dim jan 07 21:57:39 2001 (tested with kernel 2.4 & irnet/ppp) | 
 | 21 |  * Modified: 2.14 Christian Gennerat <christian.gennerat@polytechnique.org> | 
 | 22 |  * Modified: 2.14 lun fev 05 17:55:59 2001 (adapted to patch-2.4.1-pre8-irda1) | 
 | 23 |  * Modified: 2.15 Martin Lucina <mato@kotelna.sk> | 
 | 24 |  * Modified: 2.15 Fri Jun 21 20:40:59 2002 (sync with 2.4.18, substantial fixes) | 
 | 25 |  * Modified: 2.16 Martin Lucina <mato@kotelna.sk> | 
 | 26 |  * Modified: 2.16 Sat Jun 22 18:54:29 2002 (fix freeregion, default to verbose) | 
 | 27 |  * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org> | 
 | 28 |  * Modified: 2.17 jeu sep 12 08:50:20 2002 (save_flags();cli(); replaced by spinlocks) | 
 | 29 |  * Modified: 2.18 Christian Gennerat <christian.gennerat@polytechnique.org> | 
 | 30 |  * Modified: 2.18 ven jan 10 03:14:16 2003 Change probe default options | 
 | 31 |  * | 
 | 32 |  *     Copyright (c) 1999 James McKenzie, All Rights Reserved. | 
 | 33 |  * | 
 | 34 |  *     This program is free software; you can redistribute it and/or | 
 | 35 |  *     modify it under the terms of the GNU General Public License as | 
 | 36 |  *     published by the Free Software Foundation; either version 2 of | 
 | 37 |  *     the License, or (at your option) any later version. | 
 | 38 |  * | 
 | 39 |  *     Neither James McKenzie nor Cambridge University admit liability nor | 
 | 40 |  *     provide warranty for any of this software. This material is | 
 | 41 |  *     provided "AS-IS" and at no charge. | 
 | 42 |  * | 
 | 43 |  *     Applicable Models : Libretto 100/110CT and many more. | 
 | 44 |  *     Toshiba refers to this chip as the type-O IR port, | 
 | 45 |  *     or the type-DO IR port. | 
 | 46 |  * | 
 | 47 |  ********************************************************************/ | 
 | 48 |  | 
 | 49 | /* Look at toshoboe.h (currently in include/net/irda) for details of */ | 
 | 50 | /* Where to get documentation on the chip         */ | 
 | 51 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | /* See below for a description of the logic in this driver */ | 
 | 53 |  | 
 | 54 | /* User servicable parts */ | 
 | 55 | /* USE_PROBE Create the code which probes the chip and does a few tests */ | 
 | 56 | /* do_probe module parameter Enable this code */ | 
 | 57 | /* Probe code is very useful for understanding how the hardware works */ | 
 | 58 | /* Use it with various combinations of TT_LEN, RX_LEN */ | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 59 | /* Strongly recommended, disable if the probe fails on your machine */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 60 | /* and send me <james@fishsoup.dhs.org> the output of dmesg */ | 
 | 61 | #define USE_PROBE 1 | 
 | 62 | #undef  USE_PROBE | 
 | 63 |  | 
 | 64 | /* Trace Transmit ring, interrupts, Receive ring or not ? */ | 
 | 65 | #define PROBE_VERBOSE 1 | 
 | 66 |  | 
 | 67 | /* Debug option, examine sent and received raw data */ | 
 | 68 | /* Irdadump is better, but does not see all packets. enable it if you want. */ | 
 | 69 | #undef DUMP_PACKETS | 
 | 70 |  | 
 | 71 | /* MIR mode has not been tested. Some behaviour is different */ | 
 | 72 | /* Seems to work against an Ericsson R520 for me. -Martin */ | 
 | 73 | #define USE_MIR | 
 | 74 |  | 
 | 75 | /* Schedule back to back hardware transmits wherever possible, otherwise */ | 
 | 76 | /* we need an interrupt for every frame, unset if oboe works for a bit and */ | 
 | 77 | /* then hangs */ | 
 | 78 | #define OPTIMIZE_TX | 
 | 79 |  | 
 | 80 | /* Set the number of slots in the rings */ | 
 | 81 | /* If you get rx/tx fifo overflows at high bitrates, you can try increasing */ | 
 | 82 | /* these */ | 
 | 83 |  | 
 | 84 | #define RING_SIZE (OBOE_RING_SIZE_RX8 | OBOE_RING_SIZE_TX8) | 
 | 85 | #define TX_SLOTS    8 | 
 | 86 | #define RX_SLOTS    8 | 
 | 87 |  | 
 | 88 |  | 
 | 89 | /* Less user servicable parts below here */ | 
 | 90 |  | 
 | 91 | /* Test, Transmit and receive buffer sizes, adjust at your peril */ | 
 | 92 | /* remarks: nfs usually needs 1k blocks */ | 
 | 93 | /* remarks: in SIR mode, CRC is received, -> RX_LEN=TX_LEN+2 */ | 
 | 94 | /* remarks: test accepts large blocks. Standard is 0x80 */ | 
 | 95 | /* When TT_LEN > RX_LEN (SIR mode) data is stored in successive slots. */ | 
 | 96 | /* When 3 or more slots are needed for each test packet, */ | 
 | 97 | /* data received in the first slots is overwritten, even */ | 
 | 98 | /* if OBOE_CTL_RX_HW_OWNS is not set, without any error! */ | 
 | 99 | #define TT_LEN      0x80 | 
 | 100 | #define TX_LEN      0xc00 | 
 | 101 | #define RX_LEN      0xc04 | 
 | 102 | /* Real transmitted length (SIR mode) is about 14+(2%*TX_LEN) more */ | 
 | 103 | /* long than user-defined length (see async_wrap_skb) and is less then 4K */ | 
 | 104 | /* Real received length is (max RX_LEN) differs from user-defined */ | 
 | 105 | /* length only b the CRC (2 or 4 bytes) */ | 
 | 106 | #define BUF_SAFETY  0x7a | 
 | 107 | #define RX_BUF_SZ   (RX_LEN) | 
 | 108 | #define TX_BUF_SZ   (TX_LEN+BUF_SAFETY) | 
 | 109 |  | 
 | 110 |  | 
 | 111 | /* Logic of the netdev part of this driver                             */ | 
 | 112 |  | 
 | 113 | /* The RX ring is filled with buffers, when a packet arrives           */ | 
 | 114 | /* it is DMA'd into the buffer which is marked used and RxDone called  */ | 
 | 115 | /* RxDone forms an skb (and checks the CRC if in SIR mode) and ships   */ | 
 | 116 | /* the packet off upstairs */ | 
 | 117 |  | 
 | 118 | /* The transmitter on the oboe chip can work in one of two modes       */ | 
 | 119 | /* for each ring->tx[] the transmitter can either                      */ | 
 | 120 | /* a) transmit the packet, leave the trasmitter enabled and proceed to */ | 
 | 121 | /*    the next ring                                                    */ | 
 | 122 | /* OR                                                                  */ | 
 | 123 | /* b) transmit the packet, switch off the transmitter and issue TxDone */ | 
 | 124 |  | 
 | 125 | /* All packets are entered into the ring in mode b), if the ring was   */ | 
 | 126 | /* empty the transmitter is started.                                   */ | 
 | 127 |  | 
 | 128 | /* If OPTIMIZE_TX is defined then in TxDone if the ring contains       */ | 
 | 129 | /* more than one packet, all but the last are set to mode a) [HOWEVER  */ | 
 | 130 | /* the hardware may not notice this, this is why we start in mode b) ] */ | 
 | 131 | /* then restart the transmitter                                        */ | 
 | 132 |  | 
 | 133 | /* If OPTIMIZE_TX is not defined then we just restart the transmitter  */ | 
 | 134 | /* if the ring isn't empty */ | 
 | 135 |  | 
 | 136 | /* Speed changes are delayed until the TxRing is empty                 */ | 
 | 137 | /* mtt is handled by generating packets with bad CRCs, before the data */ | 
 | 138 |  | 
 | 139 | /* TODO: */ | 
 | 140 | /* check the mtt works ok      */ | 
 | 141 | /* finish the watchdog         */ | 
 | 142 |  | 
 | 143 | /* No user servicable parts below here */ | 
 | 144 |  | 
 | 145 | #include <linux/module.h> | 
 | 146 |  | 
 | 147 | #include <linux/kernel.h> | 
 | 148 | #include <linux/types.h> | 
 | 149 | #include <linux/skbuff.h> | 
 | 150 | #include <linux/netdevice.h> | 
 | 151 | #include <linux/ioport.h> | 
 | 152 | #include <linux/delay.h> | 
 | 153 | #include <linux/slab.h> | 
 | 154 | #include <linux/init.h> | 
| Alexey Dobriyan | a6b7a40 | 2011-06-06 10:43:46 +0000 | [diff] [blame] | 155 | #include <linux/interrupt.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 156 | #include <linux/pci.h> | 
 | 157 | #include <linux/rtnetlink.h> | 
 | 158 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 159 | #include <asm/io.h> | 
 | 160 |  | 
 | 161 | #include <net/irda/wrapper.h> | 
 | 162 | #include <net/irda/irda.h> | 
 | 163 | //#include <net/irda/irmod.h> | 
 | 164 | //#include <net/irda/irlap_frame.h> | 
 | 165 | #include <net/irda/irda_device.h> | 
 | 166 | #include <net/irda/crc.h> | 
 | 167 |  | 
 | 168 | #include "donauboe.h" | 
 | 169 |  | 
 | 170 | #define INB(port)       inb_p(port) | 
 | 171 | #define OUTB(val,port)  outb_p(val,port) | 
 | 172 | #define OUTBP(val,port) outb_p(val,port) | 
 | 173 |  | 
 | 174 | #define PROMPT  OUTB(OBOE_PROMPT_BIT,OBOE_PROMPT); | 
 | 175 |  | 
 | 176 | #if PROBE_VERBOSE | 
 | 177 | #define PROBE_DEBUG(args...) (printk (args)) | 
 | 178 | #else | 
 | 179 | #define PROBE_DEBUG(args...) ; | 
 | 180 | #endif | 
 | 181 |  | 
 | 182 | /* Set the DMA to be byte at a time */ | 
 | 183 | #define CONFIG0H_DMA_OFF OBOE_CONFIG0H_RCVANY | 
 | 184 | #define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC | 
 | 185 | #define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX | 
 | 186 |  | 
| Alexey Dobriyan | a3aa188 | 2010-01-07 11:58:11 +0000 | [diff] [blame] | 187 | static DEFINE_PCI_DEVICE_TABLE(toshoboe_pci_tbl) = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 188 | 	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, }, | 
 | 189 | 	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, }, | 
 | 190 | 	{ }			/* Terminating entry */ | 
 | 191 | }; | 
 | 192 | MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl); | 
 | 193 |  | 
 | 194 | #define DRIVER_NAME "toshoboe" | 
 | 195 | static char *driver_name = DRIVER_NAME; | 
 | 196 |  | 
 | 197 | static int max_baud = 4000000; | 
 | 198 | #ifdef USE_PROBE | 
| Rusty Russell | eb93992 | 2011-12-19 14:08:01 +0000 | [diff] [blame] | 199 | static bool do_probe = false; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 200 | #endif | 
 | 201 |  | 
 | 202 |  | 
 | 203 | /**********************************************************************/ | 
 | 204 | static int | 
 | 205 | toshoboe_checkfcs (unsigned char *buf, int len) | 
 | 206 | { | 
 | 207 |   int i; | 
 | 208 |   union | 
 | 209 |   { | 
 | 210 |     __u16 value; | 
 | 211 |     __u8 bytes[2]; | 
 | 212 |   } | 
 | 213 |   fcs; | 
 | 214 |  | 
 | 215 |   fcs.value = INIT_FCS; | 
 | 216 |  | 
 | 217 |   for (i = 0; i < len; ++i) | 
 | 218 |     fcs.value = irda_fcs (fcs.value, *(buf++)); | 
 | 219 |  | 
| Eric Dumazet | 807540b | 2010-09-23 05:40:09 +0000 | [diff] [blame] | 220 |   return fcs.value == GOOD_FCS; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | } | 
 | 222 |  | 
 | 223 | /***********************************************************************/ | 
 | 224 | /* Generic chip handling code */ | 
 | 225 | #ifdef DUMP_PACKETS | 
 | 226 | static unsigned char dump[50]; | 
 | 227 | static void | 
 | 228 | _dumpbufs (unsigned char *data, int len, char tete) | 
 | 229 | { | 
 | 230 | int i,j; | 
 | 231 | char head=tete; | 
 | 232 | for (i=0;i<len;i+=16) { | 
 | 233 |     for (j=0;j<16 && i+j<len;j++) { sprintf(&dump[3*j],"%02x.",data[i+j]); } | 
 | 234 |     dump [3*j]=0; | 
 | 235 |     IRDA_DEBUG (2, "%c%s\n",head , dump); | 
 | 236 |     head='+'; | 
 | 237 |     } | 
 | 238 | } | 
 | 239 | #endif | 
 | 240 |  | 
 | 241 | #ifdef USE_PROBE | 
 | 242 | /* Dump the registers */ | 
 | 243 | static void | 
 | 244 | toshoboe_dumpregs (struct toshoboe_cb *self) | 
 | 245 | { | 
 | 246 |   __u32 ringbase; | 
 | 247 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 248 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 249 |  | 
 | 250 |   ringbase = INB (OBOE_RING_BASE0) << 10; | 
 | 251 |   ringbase |= INB (OBOE_RING_BASE1) << 18; | 
 | 252 |   ringbase |= INB (OBOE_RING_BASE2) << 26; | 
 | 253 |  | 
 | 254 |   printk (KERN_ERR DRIVER_NAME ": Register dump:\n"); | 
 | 255 |   printk (KERN_ERR "Interrupts: Tx:%d Rx:%d TxUnder:%d RxOver:%d Sip:%d\n", | 
 | 256 |           self->int_tx, self->int_rx, self->int_txunder, self->int_rxover, | 
 | 257 |           self->int_sip); | 
 | 258 |   printk (KERN_ERR "RX %02x TX %02x RingBase %08x\n", | 
 | 259 |           INB (OBOE_RXSLOT), INB (OBOE_TXSLOT), ringbase); | 
 | 260 |   printk (KERN_ERR "RING_SIZE %02x IER %02x ISR %02x\n", | 
 | 261 |           INB (OBOE_RING_SIZE), INB (OBOE_IER), INB (OBOE_ISR)); | 
 | 262 |   printk (KERN_ERR "CONFIG1 %02x STATUS %02x\n", | 
 | 263 |           INB (OBOE_CONFIG1), INB (OBOE_STATUS)); | 
 | 264 |   printk (KERN_ERR "CONFIG0 %02x%02x ENABLE %02x%02x\n", | 
 | 265 |           INB (OBOE_CONFIG0H), INB (OBOE_CONFIG0L), | 
 | 266 |           INB (OBOE_ENABLEH), INB (OBOE_ENABLEL)); | 
 | 267 |   printk (KERN_ERR "NEW_PCONFIG %02x%02x CURR_PCONFIG %02x%02x\n", | 
 | 268 |           INB (OBOE_NEW_PCONFIGH), INB (OBOE_NEW_PCONFIGL), | 
 | 269 |           INB (OBOE_CURR_PCONFIGH), INB (OBOE_CURR_PCONFIGL)); | 
 | 270 |   printk (KERN_ERR "MAXLEN %02x%02x RXCOUNT %02x%02x\n", | 
 | 271 |           INB (OBOE_MAXLENH), INB (OBOE_MAXLENL), | 
 | 272 |           INB (OBOE_RXCOUNTL), INB (OBOE_RXCOUNTH)); | 
 | 273 |  | 
 | 274 |   if (self->ring) | 
 | 275 |     { | 
 | 276 |       int i; | 
 | 277 |       ringbase = virt_to_bus (self->ring); | 
 | 278 |       printk (KERN_ERR "Ring at %08x:\n", ringbase); | 
 | 279 |       printk (KERN_ERR "RX:"); | 
 | 280 |       for (i = 0; i < RX_SLOTS; ++i) | 
 | 281 |         printk (" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control); | 
 | 282 |       printk ("\n"); | 
 | 283 |       printk (KERN_ERR "TX:"); | 
 | 284 |       for (i = 0; i < RX_SLOTS; ++i) | 
 | 285 |         printk (" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control); | 
 | 286 |       printk ("\n"); | 
 | 287 |     } | 
 | 288 | } | 
 | 289 | #endif | 
 | 290 |  | 
 | 291 | /*Don't let the chip look at memory */ | 
 | 292 | static void | 
 | 293 | toshoboe_disablebm (struct toshoboe_cb *self) | 
 | 294 | { | 
 | 295 |   __u8 command; | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 296 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 297 |  | 
 | 298 |   pci_read_config_byte (self->pdev, PCI_COMMAND, &command); | 
 | 299 |   command &= ~PCI_COMMAND_MASTER; | 
 | 300 |   pci_write_config_byte (self->pdev, PCI_COMMAND, command); | 
 | 301 |  | 
 | 302 | } | 
 | 303 |  | 
 | 304 | /* Shutdown the chip and point the taskfile reg somewhere else */ | 
 | 305 | static void | 
 | 306 | toshoboe_stopchip (struct toshoboe_cb *self) | 
 | 307 | { | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 308 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 309 |  | 
 | 310 |   /*Disable interrupts */ | 
 | 311 |   OUTB (0x0, OBOE_IER); | 
 | 312 |   /*Disable DMA, Disable Rx, Disable Tx */ | 
 | 313 |   OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); | 
 | 314 |   /*Disable SIR MIR FIR, Tx and Rx */ | 
 | 315 |   OUTB (0x00, OBOE_ENABLEH); | 
 | 316 |   /*Point the ring somewhere safe */ | 
 | 317 |   OUTB (0x3f, OBOE_RING_BASE2); | 
 | 318 |   OUTB (0xff, OBOE_RING_BASE1); | 
 | 319 |   OUTB (0xff, OBOE_RING_BASE0); | 
 | 320 |  | 
 | 321 |   OUTB (RX_LEN >> 8, OBOE_MAXLENH); | 
 | 322 |   OUTB (RX_LEN & 0xff, OBOE_MAXLENL); | 
 | 323 |  | 
 | 324 |   /*Acknoledge any pending interrupts */ | 
 | 325 |   OUTB (0xff, OBOE_ISR); | 
 | 326 |  | 
 | 327 |   /*Why */ | 
 | 328 |   OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); | 
 | 329 |  | 
 | 330 |   /*switch it off */ | 
 | 331 |   OUTB (OBOE_CONFIG1_OFF, OBOE_CONFIG1); | 
 | 332 |  | 
 | 333 |   toshoboe_disablebm (self); | 
 | 334 | } | 
 | 335 |  | 
 | 336 | /* Transmitter initialization */ | 
 | 337 | static void | 
 | 338 | toshoboe_start_DMA (struct toshoboe_cb *self, int opts) | 
 | 339 | { | 
 | 340 |   OUTB (0x0, OBOE_ENABLEH); | 
 | 341 |   OUTB (CONFIG0H_DMA_ON | opts,  OBOE_CONFIG0H); | 
 | 342 |   OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); | 
 | 343 |   PROMPT; | 
 | 344 | } | 
 | 345 |  | 
 | 346 | /*Set the baud rate */ | 
 | 347 | static void | 
 | 348 | toshoboe_setbaud (struct toshoboe_cb *self) | 
 | 349 | { | 
 | 350 |   __u16 pconfig = 0; | 
 | 351 |   __u8 config0l = 0; | 
 | 352 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 353 |   IRDA_DEBUG (2, "%s(%d/%d)\n", __func__, self->speed, self->io.speed); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 354 |  | 
 | 355 |   switch (self->speed) | 
 | 356 |     { | 
 | 357 |     case 2400: | 
 | 358 |     case 4800: | 
 | 359 |     case 9600: | 
 | 360 |     case 19200: | 
 | 361 |     case 38400: | 
 | 362 |     case 57600: | 
 | 363 |     case 115200: | 
 | 364 | #ifdef USE_MIR | 
 | 365 |     case 1152000: | 
 | 366 | #endif | 
 | 367 |     case 4000000: | 
 | 368 |       break; | 
 | 369 |     default: | 
 | 370 |  | 
 | 371 |       printk (KERN_ERR DRIVER_NAME ": switch to unsupported baudrate %d\n", | 
 | 372 |               self->speed); | 
 | 373 |       return; | 
 | 374 |     } | 
 | 375 |  | 
 | 376 |   switch (self->speed) | 
 | 377 |     { | 
 | 378 |       /* For SIR the preamble is done by adding XBOFs */ | 
 | 379 |       /* to the packet */ | 
 | 380 |       /* set to filtered SIR mode, filter looks for BOF and EOF */ | 
 | 381 |     case 2400: | 
 | 382 |       pconfig |= 47 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 383 |       pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; | 
 | 384 |       break; | 
 | 385 |     case 4800: | 
 | 386 |       pconfig |= 23 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 387 |       pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; | 
 | 388 |       break; | 
 | 389 |     case 9600: | 
 | 390 |       pconfig |= 11 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 391 |       pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; | 
 | 392 |       break; | 
 | 393 |     case 19200: | 
 | 394 |       pconfig |= 5 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 395 |       pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; | 
 | 396 |       break; | 
 | 397 |     case 38400: | 
 | 398 |       pconfig |= 2 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 399 |       pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; | 
 | 400 |       break; | 
 | 401 |     case 57600: | 
 | 402 |       pconfig |= 1 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 403 |       pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; | 
 | 404 |       break; | 
 | 405 |     case 115200: | 
 | 406 |       pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 407 |       pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; | 
 | 408 |       break; | 
 | 409 |     default: | 
 | 410 |       /*Set to packet based reception */ | 
 | 411 |       OUTB (RX_LEN >> 8, OBOE_MAXLENH); | 
 | 412 |       OUTB (RX_LEN & 0xff, OBOE_MAXLENL); | 
 | 413 |       break; | 
 | 414 |     } | 
 | 415 |  | 
 | 416 |   switch (self->speed) | 
 | 417 |     { | 
 | 418 |     case 2400: | 
 | 419 |     case 4800: | 
 | 420 |     case 9600: | 
 | 421 |     case 19200: | 
 | 422 |     case 38400: | 
 | 423 |     case 57600: | 
 | 424 |     case 115200: | 
 | 425 |       config0l = OBOE_CONFIG0L_ENSIR; | 
 | 426 |       if (self->async) | 
 | 427 |         { | 
 | 428 |           /*Set to character based reception */ | 
 | 429 |           /*System will lock if MAXLEN=0 */ | 
 | 430 |           /*so have to be careful */ | 
 | 431 |           OUTB (0x01, OBOE_MAXLENH); | 
 | 432 |           OUTB (0x01, OBOE_MAXLENL); | 
 | 433 |           OUTB (0x00, OBOE_MAXLENH); | 
 | 434 |         } | 
 | 435 |       else | 
 | 436 |         { | 
 | 437 |           /*Set to packet based reception */ | 
 | 438 |           config0l |= OBOE_CONFIG0L_ENSIRF; | 
 | 439 |           OUTB (RX_LEN >> 8, OBOE_MAXLENH); | 
 | 440 |           OUTB (RX_LEN & 0xff, OBOE_MAXLENL); | 
 | 441 |         } | 
 | 442 |       break; | 
 | 443 |  | 
 | 444 | #ifdef USE_MIR | 
 | 445 |       /* MIR mode */ | 
 | 446 |       /* Set for 16 bit CRC and enable MIR */ | 
 | 447 |       /* Preamble now handled by the chip */ | 
 | 448 |     case 1152000: | 
 | 449 |       pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 450 |       pconfig |= 8 << OBOE_PCONFIG_WIDTHSHIFT; | 
 | 451 |       pconfig |= 1 << OBOE_PCONFIG_PREAMBLESHIFT; | 
 | 452 |       config0l = OBOE_CONFIG0L_CRC16 | OBOE_CONFIG0L_ENMIR; | 
 | 453 |       break; | 
 | 454 | #endif | 
 | 455 |       /* FIR mode */ | 
 | 456 |       /* Set for 32 bit CRC and enable FIR */ | 
 | 457 |       /* Preamble handled by the chip */ | 
 | 458 |     case 4000000: | 
 | 459 |       pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; | 
 | 460 |       /* Documentation says 14, but toshiba use 15 in their drivers */ | 
 | 461 |       pconfig |= 15 << OBOE_PCONFIG_PREAMBLESHIFT; | 
 | 462 |       config0l = OBOE_CONFIG0L_ENFIR; | 
 | 463 |       break; | 
 | 464 |     } | 
 | 465 |  | 
 | 466 |   /* Copy into new PHY config buffer */ | 
 | 467 |   OUTBP (pconfig >> 8, OBOE_NEW_PCONFIGH); | 
 | 468 |   OUTB (pconfig & 0xff, OBOE_NEW_PCONFIGL); | 
 | 469 |   OUTB (config0l, OBOE_CONFIG0L); | 
 | 470 |  | 
 | 471 |   /* Now make OBOE copy from new PHY to current PHY */ | 
 | 472 |   OUTB (0x0, OBOE_ENABLEH); | 
 | 473 |   OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); | 
 | 474 |   PROMPT; | 
 | 475 |  | 
 | 476 |   /* speed change executed */ | 
 | 477 |   self->new_speed = 0; | 
 | 478 |   self->io.speed = self->speed; | 
 | 479 | } | 
 | 480 |  | 
 | 481 | /*Let the chip look at memory */ | 
 | 482 | static void | 
 | 483 | toshoboe_enablebm (struct toshoboe_cb *self) | 
 | 484 | { | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 485 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 486 |   pci_set_master (self->pdev); | 
 | 487 | } | 
 | 488 |  | 
 | 489 | /*setup the ring */ | 
 | 490 | static void | 
 | 491 | toshoboe_initring (struct toshoboe_cb *self) | 
 | 492 | { | 
 | 493 |   int i; | 
 | 494 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 495 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 496 |  | 
 | 497 |   for (i = 0; i < TX_SLOTS; ++i) | 
 | 498 |     { | 
 | 499 |       self->ring->tx[i].len = 0; | 
 | 500 |       self->ring->tx[i].control = 0x00; | 
 | 501 |       self->ring->tx[i].address = virt_to_bus (self->tx_bufs[i]); | 
 | 502 |     } | 
 | 503 |  | 
 | 504 |   for (i = 0; i < RX_SLOTS; ++i) | 
 | 505 |     { | 
 | 506 |       self->ring->rx[i].len = RX_LEN; | 
 | 507 |       self->ring->rx[i].len = 0; | 
 | 508 |       self->ring->rx[i].address = virt_to_bus (self->rx_bufs[i]); | 
 | 509 |       self->ring->rx[i].control = OBOE_CTL_RX_HW_OWNS; | 
 | 510 |     } | 
 | 511 | } | 
 | 512 |  | 
 | 513 | static void | 
 | 514 | toshoboe_resetptrs (struct toshoboe_cb *self) | 
 | 515 | { | 
 | 516 |   /* Can reset pointers by twidling DMA */ | 
 | 517 |   OUTB (0x0, OBOE_ENABLEH); | 
 | 518 |   OUTBP (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); | 
 | 519 |   OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); | 
 | 520 |  | 
 | 521 |   self->rxs = inb_p (OBOE_RXSLOT) & OBOE_SLOT_MASK; | 
 | 522 |   self->txs = inb_p (OBOE_TXSLOT) & OBOE_SLOT_MASK; | 
 | 523 | } | 
 | 524 |  | 
 | 525 | /* Called in locked state */ | 
 | 526 | static void | 
 | 527 | toshoboe_initptrs (struct toshoboe_cb *self) | 
 | 528 | { | 
 | 529 |  | 
 | 530 |   /* spin_lock_irqsave(self->spinlock, flags); */ | 
 | 531 |   /* save_flags (flags); */ | 
 | 532 |  | 
 | 533 |   /* Can reset pointers by twidling DMA */ | 
 | 534 |   toshoboe_resetptrs (self); | 
 | 535 |  | 
 | 536 |   OUTB (0x0, OBOE_ENABLEH); | 
 | 537 |   OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H); | 
 | 538 |   OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); | 
 | 539 |  | 
 | 540 |   self->txpending = 0; | 
 | 541 |  | 
 | 542 |   /* spin_unlock_irqrestore(self->spinlock, flags); */ | 
 | 543 |   /* restore_flags (flags); */ | 
 | 544 | } | 
 | 545 |  | 
 | 546 | /* Wake the chip up and get it looking at the rings */ | 
 | 547 | /* Called in locked state */ | 
 | 548 | static void | 
 | 549 | toshoboe_startchip (struct toshoboe_cb *self) | 
 | 550 | { | 
 | 551 |   __u32 physaddr; | 
 | 552 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 553 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 554 |  | 
 | 555 |   toshoboe_initring (self); | 
 | 556 |   toshoboe_enablebm (self); | 
 | 557 |   OUTBP (OBOE_CONFIG1_RESET, OBOE_CONFIG1); | 
 | 558 |   OUTBP (OBOE_CONFIG1_ON, OBOE_CONFIG1); | 
 | 559 |  | 
 | 560 |   /* Stop the clocks */ | 
 | 561 |   OUTB (0, OBOE_ENABLEH); | 
 | 562 |  | 
 | 563 |   /*Set size of rings */ | 
 | 564 |   OUTB (RING_SIZE, OBOE_RING_SIZE); | 
 | 565 |  | 
 | 566 |   /*Acknoledge any pending interrupts */ | 
 | 567 |   OUTB (0xff, OBOE_ISR); | 
 | 568 |  | 
 | 569 |   /*Enable ints */ | 
 | 570 |   OUTB (OBOE_INT_TXDONE  | OBOE_INT_RXDONE | | 
 | 571 |         OBOE_INT_TXUNDER | OBOE_INT_RXOVER | OBOE_INT_SIP , OBOE_IER); | 
 | 572 |  | 
 | 573 |   /*Acknoledge any pending interrupts */ | 
 | 574 |   OUTB (0xff, OBOE_ISR); | 
 | 575 |  | 
 | 576 |   /*Set the maximum packet length to 0xfff (4095) */ | 
 | 577 |   OUTB (RX_LEN >> 8, OBOE_MAXLENH); | 
 | 578 |   OUTB (RX_LEN & 0xff, OBOE_MAXLENL); | 
 | 579 |  | 
 | 580 |   /*Shutdown DMA */ | 
 | 581 |   OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); | 
 | 582 |  | 
 | 583 |   /*Find out where the rings live */ | 
 | 584 |   physaddr = virt_to_bus (self->ring); | 
 | 585 |  | 
 | 586 |   IRDA_ASSERT ((physaddr & 0x3ff) == 0, | 
 | 587 | 	       printk (KERN_ERR DRIVER_NAME "ring not correctly aligned\n"); | 
 | 588 | 	       return;); | 
 | 589 |  | 
 | 590 |   OUTB ((physaddr >> 10) & 0xff, OBOE_RING_BASE0); | 
 | 591 |   OUTB ((physaddr >> 18) & 0xff, OBOE_RING_BASE1); | 
 | 592 |   OUTB ((physaddr >> 26) & 0x3f, OBOE_RING_BASE2); | 
 | 593 |  | 
| Robert P. J. Day | 3a4fa0a | 2007-10-19 23:10:43 +0200 | [diff] [blame] | 594 |   /*Enable DMA controller in byte mode and RX */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 595 |   OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H); | 
 | 596 |  | 
 | 597 |   /* Start up the clocks */ | 
 | 598 |   OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); | 
 | 599 |  | 
 | 600 |   /*set to sensible speed */ | 
 | 601 |   self->speed = 9600; | 
 | 602 |   toshoboe_setbaud (self); | 
 | 603 |   toshoboe_initptrs (self); | 
 | 604 | } | 
 | 605 |  | 
 | 606 | static void | 
 | 607 | toshoboe_isntstuck (struct toshoboe_cb *self) | 
 | 608 | { | 
 | 609 | } | 
 | 610 |  | 
 | 611 | static void | 
 | 612 | toshoboe_checkstuck (struct toshoboe_cb *self) | 
 | 613 | { | 
 | 614 |   unsigned long flags; | 
 | 615 |  | 
 | 616 |   if (0) | 
 | 617 |     { | 
 | 618 |       spin_lock_irqsave(&self->spinlock, flags); | 
 | 619 |  | 
 | 620 |       /* This will reset the chip completely */ | 
 | 621 |       printk (KERN_ERR DRIVER_NAME ": Resetting chip\n"); | 
 | 622 |  | 
 | 623 |       toshoboe_stopchip (self); | 
 | 624 |       toshoboe_startchip (self); | 
 | 625 |       spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 626 |     } | 
 | 627 | } | 
 | 628 |  | 
 | 629 | /*Generate packet of about mtt us long */ | 
 | 630 | static int | 
 | 631 | toshoboe_makemttpacket (struct toshoboe_cb *self, void *buf, int mtt) | 
 | 632 | { | 
 | 633 |   int xbofs; | 
 | 634 |  | 
 | 635 |   xbofs = ((int) (mtt/100)) * (int) (self->speed); | 
 | 636 |   xbofs=xbofs/80000; /*Eight bits per byte, and mtt is in us*/ | 
 | 637 |   xbofs++; | 
 | 638 |  | 
 | 639 |   IRDA_DEBUG (2, DRIVER_NAME | 
 | 640 |       ": generated mtt of %d bytes for %d us at %d baud\n" | 
 | 641 | 	  , xbofs,mtt,self->speed); | 
 | 642 |  | 
 | 643 |   if (xbofs > TX_LEN) | 
 | 644 |     { | 
 | 645 |       printk (KERN_ERR DRIVER_NAME ": wanted %d bytes MTT but TX_LEN is %d\n", | 
 | 646 |               xbofs, TX_LEN); | 
 | 647 |       xbofs = TX_LEN; | 
 | 648 |     } | 
 | 649 |  | 
 | 650 |   /*xbofs will do for SIR, MIR and FIR,SIR mode doesn't generate a checksum anyway */ | 
 | 651 |   memset (buf, XBOF, xbofs); | 
 | 652 |  | 
 | 653 |   return xbofs; | 
 | 654 | } | 
 | 655 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 656 | #ifdef USE_PROBE | 
 | 657 | /***********************************************************************/ | 
 | 658 | /* Probe code */ | 
 | 659 |  | 
 | 660 | static void | 
 | 661 | toshoboe_dumptx (struct toshoboe_cb *self) | 
 | 662 | { | 
 | 663 |   int i; | 
 | 664 |   PROBE_DEBUG(KERN_WARNING "TX:"); | 
 | 665 |   for (i = 0; i < RX_SLOTS; ++i) | 
 | 666 |     PROBE_DEBUG(" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control); | 
 | 667 |   PROBE_DEBUG(" [%d]\n",self->speed); | 
 | 668 | } | 
 | 669 |  | 
 | 670 | static void | 
 | 671 | toshoboe_dumprx (struct toshoboe_cb *self, int score) | 
 | 672 | { | 
 | 673 |   int i; | 
 | 674 |   PROBE_DEBUG(" %d\nRX:",score); | 
 | 675 |   for (i = 0; i < RX_SLOTS; ++i) | 
 | 676 |     PROBE_DEBUG(" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control); | 
 | 677 |   PROBE_DEBUG("\n"); | 
 | 678 | } | 
 | 679 |  | 
 | 680 | static inline int | 
 | 681 | stuff_byte (__u8 byte, __u8 * buf) | 
 | 682 | { | 
 | 683 |   switch (byte) | 
 | 684 |     { | 
 | 685 |     case BOF:                  /* FALLTHROUGH */ | 
 | 686 |     case EOF:                  /* FALLTHROUGH */ | 
 | 687 |     case CE: | 
 | 688 |       /* Insert transparently coded */ | 
 | 689 |       buf[0] = CE;              /* Send link escape */ | 
 | 690 |       buf[1] = byte ^ IRDA_TRANS; /* Complement bit 5 */ | 
 | 691 |       return 2; | 
 | 692 |       /* break; */ | 
 | 693 |     default: | 
 | 694 |       /* Non-special value, no transparency required */ | 
 | 695 |       buf[0] = byte; | 
 | 696 |       return 1; | 
 | 697 |       /* break; */ | 
 | 698 |     } | 
 | 699 | } | 
 | 700 |  | 
 | 701 | static irqreturn_t | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 702 | toshoboe_probeinterrupt (int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 703 | { | 
| Jeff Garzik | c31f28e | 2006-10-06 14:56:04 -0400 | [diff] [blame] | 704 |   struct toshoboe_cb *self = dev_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 705 |   __u8 irqstat; | 
 | 706 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 707 |   irqstat = INB (OBOE_ISR); | 
 | 708 |  | 
 | 709 | /* was it us */ | 
 | 710 |   if (!(irqstat & OBOE_INT_MASK)) | 
 | 711 |     return IRQ_NONE; | 
 | 712 |  | 
 | 713 | /* Ack all the interrupts */ | 
 | 714 |   OUTB (irqstat, OBOE_ISR); | 
 | 715 |  | 
 | 716 |   if (irqstat & OBOE_INT_TXDONE) | 
 | 717 |     { | 
 | 718 |       int txp; | 
 | 719 |  | 
 | 720 |       self->int_tx++; | 
 | 721 |       PROBE_DEBUG("T"); | 
 | 722 |  | 
 | 723 |       txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK; | 
 | 724 |       if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS) | 
 | 725 |         { | 
 | 726 |           self->int_tx+=100; | 
 | 727 |           PROBE_DEBUG("S"); | 
 | 728 |           toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); | 
 | 729 |         } | 
 | 730 |     } | 
 | 731 |  | 
 | 732 |   if (irqstat & OBOE_INT_RXDONE) { | 
 | 733 |     self->int_rx++; | 
 | 734 |     PROBE_DEBUG("R"); } | 
 | 735 |   if (irqstat & OBOE_INT_TXUNDER) { | 
 | 736 |     self->int_txunder++; | 
 | 737 |     PROBE_DEBUG("U"); } | 
 | 738 |   if (irqstat & OBOE_INT_RXOVER) { | 
 | 739 |     self->int_rxover++; | 
 | 740 |     PROBE_DEBUG("O"); } | 
 | 741 |   if (irqstat & OBOE_INT_SIP) { | 
 | 742 |     self->int_sip++; | 
 | 743 |     PROBE_DEBUG("I"); } | 
 | 744 |   return IRQ_HANDLED; | 
 | 745 | } | 
 | 746 |  | 
 | 747 | static int | 
 | 748 | toshoboe_maketestpacket (unsigned char *buf, int badcrc, int fir) | 
 | 749 | { | 
 | 750 |   int i; | 
 | 751 |   int len = 0; | 
 | 752 |   union | 
 | 753 |   { | 
 | 754 |     __u16 value; | 
 | 755 |     __u8 bytes[2]; | 
 | 756 |   } | 
 | 757 |   fcs; | 
 | 758 |  | 
 | 759 |   if (fir) | 
 | 760 |     { | 
 | 761 |       memset (buf, 0, TT_LEN); | 
| Eric Dumazet | 807540b | 2010-09-23 05:40:09 +0000 | [diff] [blame] | 762 |       return TT_LEN; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 763 |     } | 
 | 764 |  | 
 | 765 |   fcs.value = INIT_FCS; | 
 | 766 |  | 
 | 767 |   memset (buf, XBOF, 10); | 
 | 768 |   len += 10; | 
 | 769 |   buf[len++] = BOF; | 
 | 770 |  | 
 | 771 |   for (i = 0; i < TT_LEN; ++i) | 
 | 772 |     { | 
 | 773 |       len += stuff_byte (i, buf + len); | 
 | 774 |       fcs.value = irda_fcs (fcs.value, i); | 
 | 775 |     } | 
 | 776 |  | 
 | 777 |   len += stuff_byte (fcs.bytes[0] ^ badcrc, buf + len); | 
 | 778 |   len += stuff_byte (fcs.bytes[1] ^ badcrc, buf + len); | 
 | 779 |   buf[len++] = EOF; | 
 | 780 |   len++; | 
 | 781 |   return len; | 
 | 782 | } | 
 | 783 |  | 
 | 784 | static int | 
 | 785 | toshoboe_probefail (struct toshoboe_cb *self, char *msg) | 
 | 786 | { | 
 | 787 |   printk (KERN_ERR DRIVER_NAME "probe(%d) failed %s\n",self-> speed, msg); | 
 | 788 |   toshoboe_dumpregs (self); | 
 | 789 |   toshoboe_stopchip (self); | 
 | 790 |   free_irq (self->io.irq, (void *) self); | 
 | 791 |   return 0; | 
 | 792 | } | 
 | 793 |  | 
 | 794 | static int | 
 | 795 | toshoboe_numvalidrcvs (struct toshoboe_cb *self) | 
 | 796 | { | 
 | 797 |   int i, ret = 0; | 
 | 798 |   for (i = 0; i < RX_SLOTS; ++i) | 
 | 799 |     if ((self->ring->rx[i].control & 0xe0) == 0) | 
 | 800 |       ret++; | 
 | 801 |  | 
 | 802 |   return ret; | 
 | 803 | } | 
 | 804 |  | 
 | 805 | static int | 
 | 806 | toshoboe_numrcvs (struct toshoboe_cb *self) | 
 | 807 | { | 
 | 808 |   int i, ret = 0; | 
 | 809 |   for (i = 0; i < RX_SLOTS; ++i) | 
 | 810 |     if (!(self->ring->rx[i].control & OBOE_CTL_RX_HW_OWNS)) | 
 | 811 |       ret++; | 
 | 812 |  | 
 | 813 |   return ret; | 
 | 814 | } | 
 | 815 |  | 
 | 816 | static int | 
 | 817 | toshoboe_probe (struct toshoboe_cb *self) | 
 | 818 | { | 
 | 819 |   int i, j, n; | 
 | 820 | #ifdef USE_MIR | 
| Joe Perches | 215faf9 | 2010-12-21 02:16:10 -0800 | [diff] [blame] | 821 |   static const int bauds[] = { 9600, 115200, 4000000, 1152000 }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 822 | #else | 
| Joe Perches | 215faf9 | 2010-12-21 02:16:10 -0800 | [diff] [blame] | 823 |   static const int bauds[] = { 9600, 115200, 4000000 }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 824 | #endif | 
 | 825 |   unsigned long flags; | 
 | 826 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 827 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 828 |  | 
 | 829 |   if (request_irq (self->io.irq, toshoboe_probeinterrupt, | 
 | 830 |                    self->io.irqflags, "toshoboe", (void *) self)) | 
 | 831 |     { | 
 | 832 |       printk (KERN_ERR DRIVER_NAME ": probe failed to allocate irq %d\n", | 
 | 833 |               self->io.irq); | 
 | 834 |       return 0; | 
 | 835 |     } | 
 | 836 |  | 
 | 837 |   /* test 1: SIR filter and back to back */ | 
 | 838 |  | 
| Alejandro Martinez Ruiz | e9edda6 | 2007-10-15 03:37:43 +0200 | [diff] [blame] | 839 |   for (j = 0; j < ARRAY_SIZE(bauds); ++j) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 840 |     { | 
 | 841 |       int fir = (j > 1); | 
 | 842 |       toshoboe_stopchip (self); | 
 | 843 |  | 
 | 844 |  | 
 | 845 |       spin_lock_irqsave(&self->spinlock, flags); | 
 | 846 |       /*Address is already setup */ | 
 | 847 |       toshoboe_startchip (self); | 
 | 848 |       self->int_rx = self->int_tx = 0; | 
 | 849 |       self->speed = bauds[j]; | 
 | 850 |       toshoboe_setbaud (self); | 
 | 851 |       toshoboe_initptrs (self); | 
 | 852 |       spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 853 |  | 
 | 854 |       self->ring->tx[self->txs].control = | 
 | 855 | /*   (FIR only) OBOE_CTL_TX_SIP needed for switching to next slot */ | 
 | 856 | /*    MIR: all received data is stored in one slot */ | 
 | 857 |         (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX | 
 | 858 |               : OBOE_CTL_TX_HW_OWNS ; | 
 | 859 |       self->ring->tx[self->txs].len = | 
 | 860 |         toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); | 
 | 861 |       self->txs++; | 
 | 862 |       self->txs %= TX_SLOTS; | 
 | 863 |  | 
 | 864 |       self->ring->tx[self->txs].control = | 
 | 865 |         (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_SIP | 
 | 866 |               : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ; | 
 | 867 |       self->ring->tx[self->txs].len = | 
 | 868 |         toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); | 
 | 869 |       self->txs++; | 
 | 870 |       self->txs %= TX_SLOTS; | 
 | 871 |  | 
 | 872 |       self->ring->tx[self->txs].control = | 
 | 873 |         (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX | 
 | 874 |               : OBOE_CTL_TX_HW_OWNS ; | 
 | 875 |       self->ring->tx[self->txs].len = | 
 | 876 |         toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); | 
 | 877 |       self->txs++; | 
 | 878 |       self->txs %= TX_SLOTS; | 
 | 879 |  | 
 | 880 |       self->ring->tx[self->txs].control = | 
 | 881 |         (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX | 
 | 882 |               | OBOE_CTL_TX_SIP     | OBOE_CTL_TX_BAD_CRC | 
 | 883 |               : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ; | 
 | 884 |       self->ring->tx[self->txs].len = | 
 | 885 |         toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); | 
 | 886 |       self->txs++; | 
 | 887 |       self->txs %= TX_SLOTS; | 
 | 888 |  | 
 | 889 |       toshoboe_dumptx (self); | 
 | 890 |       /* Turn on TX and RX and loopback */ | 
 | 891 |       toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); | 
 | 892 |  | 
 | 893 |       i = 0; | 
 | 894 |       n = fir ? 1 : 4; | 
 | 895 |       while (toshoboe_numvalidrcvs (self) != n) | 
 | 896 |         { | 
 | 897 |           if (i > 4800) | 
 | 898 |               return toshoboe_probefail (self, "filter test"); | 
 | 899 |           udelay ((9600*(TT_LEN+16))/self->speed); | 
 | 900 |           i++; | 
 | 901 |         } | 
 | 902 |  | 
 | 903 |       n = fir ? 203 : 102; | 
 | 904 |       while ((toshoboe_numrcvs(self) != self->int_rx) || (self->int_tx != n)) | 
 | 905 |         { | 
 | 906 |           if (i > 4800) | 
 | 907 |               return toshoboe_probefail (self, "interrupt test"); | 
 | 908 |           udelay ((9600*(TT_LEN+16))/self->speed); | 
 | 909 |           i++; | 
 | 910 |         } | 
 | 911 |      toshoboe_dumprx (self,i); | 
 | 912 |  | 
 | 913 |      } | 
 | 914 |  | 
 | 915 |   /* test 2: SIR in char at a time */ | 
 | 916 |  | 
 | 917 |   toshoboe_stopchip (self); | 
 | 918 |   self->int_rx = self->int_tx = 0; | 
 | 919 |  | 
 | 920 |   spin_lock_irqsave(&self->spinlock, flags); | 
 | 921 |   toshoboe_startchip (self); | 
 | 922 |   spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 923 |  | 
 | 924 |   self->async = 1; | 
 | 925 |   self->speed = 115200; | 
 | 926 |   toshoboe_setbaud (self); | 
 | 927 |   self->ring->tx[self->txs].control = | 
 | 928 |     OBOE_CTL_TX_RTCENTX | OBOE_CTL_TX_HW_OWNS; | 
 | 929 |   self->ring->tx[self->txs].len = 4; | 
 | 930 |  | 
 | 931 |   ((unsigned char *) self->tx_bufs[self->txs])[0] = 'f'; | 
 | 932 |   ((unsigned char *) self->tx_bufs[self->txs])[1] = 'i'; | 
 | 933 |   ((unsigned char *) self->tx_bufs[self->txs])[2] = 's'; | 
 | 934 |   ((unsigned char *) self->tx_bufs[self->txs])[3] = 'h'; | 
 | 935 |   toshoboe_dumptx (self); | 
 | 936 |   toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); | 
 | 937 |  | 
 | 938 |   i = 0; | 
 | 939 |   while (toshoboe_numvalidrcvs (self) != 4) | 
 | 940 |     { | 
 | 941 |       if (i > 100) | 
 | 942 |           return toshoboe_probefail (self, "Async test"); | 
 | 943 |       udelay (100); | 
 | 944 |       i++; | 
 | 945 |     } | 
 | 946 |  | 
 | 947 |   while ((toshoboe_numrcvs (self) != self->int_rx) || (self->int_tx != 1)) | 
 | 948 |     { | 
 | 949 |       if (i > 100) | 
 | 950 |           return toshoboe_probefail (self, "Async interrupt test"); | 
 | 951 |       udelay (100); | 
 | 952 |       i++; | 
 | 953 |     } | 
 | 954 |   toshoboe_dumprx (self,i); | 
 | 955 |  | 
 | 956 |   self->async = 0; | 
 | 957 |   self->speed = 9600; | 
 | 958 |   toshoboe_setbaud (self); | 
 | 959 |   toshoboe_stopchip (self); | 
 | 960 |  | 
 | 961 |   free_irq (self->io.irq, (void *) self); | 
 | 962 |  | 
 | 963 |   printk (KERN_WARNING DRIVER_NAME ": Self test passed ok\n"); | 
 | 964 |  | 
 | 965 |   return 1; | 
 | 966 | } | 
 | 967 | #endif | 
 | 968 |  | 
 | 969 | /******************************************************************/ | 
 | 970 | /* Netdev style code */ | 
 | 971 |  | 
 | 972 | /* Transmit something */ | 
| Stephen Hemminger | 6518bbb | 2009-08-31 19:50:50 +0000 | [diff] [blame] | 973 | static netdev_tx_t | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 974 | toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) | 
 | 975 | { | 
 | 976 |   struct toshoboe_cb *self; | 
 | 977 |   __s32 speed; | 
 | 978 |   int mtt, len, ctl; | 
 | 979 |   unsigned long flags; | 
 | 980 |   struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; | 
 | 981 |  | 
| Wang Chen | 4cf1653 | 2008-11-12 23:38:14 -0800 | [diff] [blame] | 982 |   self = netdev_priv(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 983 |  | 
| Patrick McHardy | ec634fe | 2009-07-05 19:23:38 -0700 | [diff] [blame] | 984 |   IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; ); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 985 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 986 |   IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 987 |       ,skb->len,self->txpending,INB (OBOE_ENABLEH)); | 
 | 988 |   if (!cb->magic) { | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 989 |       IRDA_DEBUG (2, "%s.Not IrLAP:%x\n", __func__, cb->magic); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 990 | #ifdef DUMP_PACKETS | 
 | 991 |       _dumpbufs(skb->data,skb->len,'>'); | 
 | 992 | #endif | 
 | 993 |     } | 
 | 994 |  | 
 | 995 |   /* change speed pending, wait for its execution */ | 
 | 996 |   if (self->new_speed) | 
| Patrick McHardy | 4bd73ae | 2009-06-12 03:17:19 +0000 | [diff] [blame] | 997 |       return NETDEV_TX_BUSY; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 998 |  | 
 | 999 |   /* device stopped (apm) wait for restart */ | 
 | 1000 |   if (self->stopped) | 
| Patrick McHardy | 4bd73ae | 2009-06-12 03:17:19 +0000 | [diff] [blame] | 1001 |       return NETDEV_TX_BUSY; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1002 |  | 
 | 1003 |   toshoboe_checkstuck (self); | 
 | 1004 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1005 |  /* Check if we need to change the speed */ | 
 | 1006 |   /* But not now. Wait after transmission if mtt not required */ | 
 | 1007 |   speed=irda_get_next_speed(skb); | 
 | 1008 |   if ((speed != self->io.speed) && (speed != -1)) | 
 | 1009 |     { | 
 | 1010 |       spin_lock_irqsave(&self->spinlock, flags); | 
 | 1011 |  | 
 | 1012 |       if (self->txpending || skb->len) | 
 | 1013 |         { | 
 | 1014 |           self->new_speed = speed; | 
 | 1015 |           IRDA_DEBUG (1, "%s: Queued TxDone scheduled speed change %d\n" , | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1016 | 		      __func__, speed); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1017 |           /* if no data, that's all! */ | 
 | 1018 |           if (!skb->len) | 
 | 1019 |             { | 
 | 1020 | 	      spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1021 |               dev_kfree_skb (skb); | 
| Patrick McHardy | 6ed1065 | 2009-06-23 06:03:08 +0000 | [diff] [blame] | 1022 |               return NETDEV_TX_OK; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1023 |             } | 
 | 1024 |           /* True packet, go on, but */ | 
 | 1025 |           /* do not accept anything before change speed execution */ | 
 | 1026 |           netif_stop_queue(dev); | 
 | 1027 |           /* ready to process TxDone interrupt */ | 
 | 1028 | 	  spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1029 |         } | 
 | 1030 |       else | 
 | 1031 |         { | 
 | 1032 |           /* idle and no data, change speed now */ | 
 | 1033 |           self->speed = speed; | 
 | 1034 |           toshoboe_setbaud (self); | 
 | 1035 | 	  spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1036 |           dev_kfree_skb (skb); | 
| Patrick McHardy | 6ed1065 | 2009-06-23 06:03:08 +0000 | [diff] [blame] | 1037 |           return NETDEV_TX_OK; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1038 |         } | 
 | 1039 |  | 
 | 1040 |     } | 
 | 1041 |  | 
 | 1042 |   if ((mtt = irda_get_mtt(skb))) | 
 | 1043 |     { | 
 | 1044 |       /* This is fair since the queue should be empty anyway */ | 
 | 1045 |       spin_lock_irqsave(&self->spinlock, flags); | 
 | 1046 |  | 
 | 1047 |       if (self->txpending) | 
 | 1048 |         { | 
 | 1049 | 	  spin_unlock_irqrestore(&self->spinlock, flags); | 
| Patrick McHardy | 4bd73ae | 2009-06-12 03:17:19 +0000 | [diff] [blame] | 1050 |           return NETDEV_TX_BUSY; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1051 |         } | 
 | 1052 |  | 
 | 1053 |       /* If in SIR mode we need to generate a string of XBOFs */ | 
 | 1054 |       /* In MIR and FIR we need to generate a string of data */ | 
 | 1055 |       /* which we will add a wrong checksum to */ | 
 | 1056 |  | 
 | 1057 |       mtt = toshoboe_makemttpacket (self, self->tx_bufs[self->txs], mtt); | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1058 |       IRDA_DEBUG (1, "%s.mtt:%x(%x)%d\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1059 |           ,skb->len,mtt,self->txpending); | 
 | 1060 |       if (mtt) | 
 | 1061 |         { | 
 | 1062 |           self->ring->tx[self->txs].len = mtt & 0xfff; | 
 | 1063 |  | 
 | 1064 |           ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX; | 
 | 1065 |           if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON) | 
 | 1066 |             { | 
 | 1067 |               ctl |= OBOE_CTL_TX_BAD_CRC | OBOE_CTL_TX_SIP ; | 
 | 1068 |             } | 
 | 1069 | #ifdef USE_MIR | 
 | 1070 |           else if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_MIRON) | 
 | 1071 |             { | 
 | 1072 |               ctl |= OBOE_CTL_TX_BAD_CRC; | 
 | 1073 |             } | 
 | 1074 | #endif | 
 | 1075 |           self->ring->tx[self->txs].control = ctl; | 
 | 1076 |  | 
 | 1077 |           OUTB (0x0, OBOE_ENABLEH); | 
 | 1078 |           /* It is only a timer. Do not send mtt packet outside! */ | 
 | 1079 |           toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); | 
 | 1080 |  | 
 | 1081 |           self->txpending++; | 
 | 1082 |  | 
 | 1083 |           self->txs++; | 
 | 1084 |           self->txs %= TX_SLOTS; | 
 | 1085 |  | 
 | 1086 |         } | 
 | 1087 |       else | 
 | 1088 |         { | 
 | 1089 |           printk(KERN_ERR DRIVER_NAME ": problem with mtt packet - ignored\n"); | 
 | 1090 |         } | 
 | 1091 |       spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1092 |     } | 
 | 1093 |  | 
 | 1094 | #ifdef DUMP_PACKETS | 
 | 1095 | dumpbufs(skb->data,skb->len,'>'); | 
 | 1096 | #endif | 
 | 1097 |  | 
 | 1098 |   spin_lock_irqsave(&self->spinlock, flags); | 
 | 1099 |  | 
 | 1100 |   if (self->ring->tx[self->txs].control & OBOE_CTL_TX_HW_OWNS) | 
 | 1101 |     { | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1102 |       IRDA_DEBUG (0, "%s.ful:%x(%x)%x\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1103 |           ,skb->len, self->ring->tx[self->txs].control, self->txpending); | 
 | 1104 |       toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); | 
 | 1105 |       spin_unlock_irqrestore(&self->spinlock, flags); | 
| Patrick McHardy | 4bd73ae | 2009-06-12 03:17:19 +0000 | [diff] [blame] | 1106 |       return NETDEV_TX_BUSY; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1107 |     } | 
 | 1108 |  | 
 | 1109 |   if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON) | 
 | 1110 |     { | 
 | 1111 |       len = async_wrap_skb (skb, self->tx_bufs[self->txs], TX_BUF_SZ); | 
 | 1112 |     } | 
 | 1113 |   else | 
 | 1114 |     { | 
 | 1115 |       len = skb->len; | 
| Arnaldo Carvalho de Melo | d626f62 | 2007-03-27 18:55:52 -0300 | [diff] [blame] | 1116 |       skb_copy_from_linear_data(skb, self->tx_bufs[self->txs], len); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1117 |     } | 
 | 1118 |   self->ring->tx[self->txs].len = len & 0x0fff; | 
 | 1119 |  | 
 | 1120 |   /*Sometimes the HW doesn't see us assert RTCENTX in the interrupt code */ | 
 | 1121 |   /*later this plays safe, we garuntee the last packet to be transmitted */ | 
 | 1122 |   /*has RTCENTX set */ | 
 | 1123 |  | 
 | 1124 |   ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX; | 
 | 1125 |   if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON) | 
 | 1126 |     { | 
 | 1127 |       ctl |= OBOE_CTL_TX_SIP ; | 
 | 1128 |     } | 
 | 1129 |   self->ring->tx[self->txs].control = ctl; | 
 | 1130 |  | 
 | 1131 |   /* If transmitter is idle start in one-shot mode */ | 
 | 1132 |  | 
 | 1133 |   if (!self->txpending) | 
 | 1134 |       toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); | 
 | 1135 |  | 
 | 1136 |   self->txpending++; | 
 | 1137 |  | 
 | 1138 |   self->txs++; | 
 | 1139 |   self->txs %= TX_SLOTS; | 
 | 1140 |  | 
 | 1141 |   spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1142 |   dev_kfree_skb (skb); | 
 | 1143 |  | 
| Patrick McHardy | 6ed1065 | 2009-06-23 06:03:08 +0000 | [diff] [blame] | 1144 |   return NETDEV_TX_OK; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1145 | } | 
 | 1146 |  | 
 | 1147 | /*interrupt handler */ | 
 | 1148 | static irqreturn_t | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 1149 | toshoboe_interrupt (int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1150 | { | 
| Jeff Garzik | 15e541f | 2006-10-10 01:40:55 -0400 | [diff] [blame] | 1151 |   struct toshoboe_cb *self = dev_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1152 |   __u8 irqstat; | 
 | 1153 |   struct sk_buff *skb = NULL; | 
 | 1154 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1155 |   irqstat = INB (OBOE_ISR); | 
 | 1156 |  | 
 | 1157 | /* was it us */ | 
 | 1158 |   if (!(irqstat & OBOE_INT_MASK)) | 
 | 1159 |       return IRQ_NONE; | 
 | 1160 |  | 
 | 1161 | /* Ack all the interrupts */ | 
 | 1162 |   OUTB (irqstat, OBOE_ISR); | 
 | 1163 |  | 
 | 1164 |   toshoboe_isntstuck (self); | 
 | 1165 |  | 
 | 1166 | /* Txdone */ | 
 | 1167 |   if (irqstat & OBOE_INT_TXDONE) | 
 | 1168 |     { | 
 | 1169 |       int txp, txpc; | 
 | 1170 |       int i; | 
 | 1171 |  | 
 | 1172 |       txp = self->txpending; | 
 | 1173 |       self->txpending = 0; | 
 | 1174 |  | 
 | 1175 |       for (i = 0; i < TX_SLOTS; ++i) | 
 | 1176 |         { | 
 | 1177 |           if (self->ring->tx[i].control & OBOE_CTL_TX_HW_OWNS) | 
 | 1178 |               self->txpending++; | 
 | 1179 |         } | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1180 |       IRDA_DEBUG (1, "%s.txd(%x)%x/%x\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1181 |           ,irqstat,txp,self->txpending); | 
 | 1182 |  | 
 | 1183 |       txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK; | 
 | 1184 |  | 
 | 1185 |       /* Got anything queued ? start it together */ | 
 | 1186 |       if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS) | 
 | 1187 |         { | 
 | 1188 |           txpc = txp; | 
 | 1189 | #ifdef OPTIMIZE_TX | 
 | 1190 |           while (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS) | 
 | 1191 |             { | 
 | 1192 |               txp = txpc; | 
 | 1193 |               txpc++; | 
 | 1194 |               txpc %= TX_SLOTS; | 
| Alexander Beregalov | 216c32d | 2009-01-08 16:42:08 -0800 | [diff] [blame] | 1195 |               self->netdev->stats.tx_packets++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1196 |               if (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS) | 
 | 1197 |                   self->ring->tx[txp].control &= ~OBOE_CTL_TX_RTCENTX; | 
 | 1198 |             } | 
| Alexander Beregalov | 216c32d | 2009-01-08 16:42:08 -0800 | [diff] [blame] | 1199 |           self->netdev->stats.tx_packets--; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1200 | #else | 
| Alexander Beregalov | 216c32d | 2009-01-08 16:42:08 -0800 | [diff] [blame] | 1201 |           self->netdev->stats.tx_packets++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1202 | #endif | 
 | 1203 |           toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); | 
 | 1204 |         } | 
 | 1205 |  | 
 | 1206 |       if ((!self->txpending) && (self->new_speed)) | 
 | 1207 |         { | 
 | 1208 |           self->speed = self->new_speed; | 
 | 1209 |           IRDA_DEBUG (1, "%s: Executed TxDone scheduled speed change %d\n", | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1210 | 		      __func__, self->speed); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1211 |           toshoboe_setbaud (self); | 
 | 1212 |         } | 
 | 1213 |  | 
 | 1214 |       /* Tell network layer that we want more frames */ | 
 | 1215 |       if (!self->new_speed) | 
 | 1216 |           netif_wake_queue(self->netdev); | 
 | 1217 |     } | 
 | 1218 |  | 
 | 1219 |   if (irqstat & OBOE_INT_RXDONE) | 
 | 1220 |     { | 
 | 1221 |       while (!(self->ring->rx[self->rxs].control & OBOE_CTL_RX_HW_OWNS)) | 
 | 1222 |         { | 
 | 1223 |           int len = self->ring->rx[self->rxs].len; | 
 | 1224 |           skb = NULL; | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1225 |           IRDA_DEBUG (3, "%s.rcv:%x(%x)\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1226 | 		      ,len,self->ring->rx[self->rxs].control); | 
 | 1227 |  | 
 | 1228 | #ifdef DUMP_PACKETS | 
 | 1229 | dumpbufs(self->rx_bufs[self->rxs],len,'<'); | 
 | 1230 | #endif | 
 | 1231 |  | 
 | 1232 |           if (self->ring->rx[self->rxs].control == 0) | 
 | 1233 |             { | 
 | 1234 |               __u8 enable = INB (OBOE_ENABLEH); | 
 | 1235 |  | 
 | 1236 |               /* In SIR mode we need to check the CRC as this */ | 
 | 1237 |               /* hasn't been done by the hardware */ | 
 | 1238 |               if (enable & OBOE_ENABLEH_SIRON) | 
 | 1239 |                 { | 
 | 1240 |                   if (!toshoboe_checkfcs (self->rx_bufs[self->rxs], len)) | 
 | 1241 |                       len = 0; | 
 | 1242 |                   /*Trim off the CRC */ | 
 | 1243 |                   if (len > 1) | 
 | 1244 |                       len -= 2; | 
 | 1245 |                   else | 
 | 1246 |                       len = 0; | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1247 |                   IRDA_DEBUG (1, "%s.SIR:%x(%x)\n", __func__, len,enable); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1248 |                 } | 
 | 1249 |  | 
 | 1250 | #ifdef USE_MIR | 
 | 1251 |               else if (enable & OBOE_ENABLEH_MIRON) | 
 | 1252 |                 { | 
 | 1253 |                   if (len > 1) | 
 | 1254 |                       len -= 2; | 
 | 1255 |                   else | 
 | 1256 |                       len = 0; | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1257 |                   IRDA_DEBUG (2, "%s.MIR:%x(%x)\n", __func__, len,enable); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1258 |                 } | 
 | 1259 | #endif | 
 | 1260 |               else if (enable & OBOE_ENABLEH_FIRON) | 
 | 1261 |                 { | 
 | 1262 |                   if (len > 3) | 
 | 1263 |                       len -= 4;   /*FIXME: check this */ | 
 | 1264 |                   else | 
 | 1265 |                       len = 0; | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1266 |                   IRDA_DEBUG (1, "%s.FIR:%x(%x)\n", __func__, len,enable); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1267 |                 } | 
 | 1268 |               else | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1269 |                   IRDA_DEBUG (0, "%s.?IR:%x(%x)\n", __func__, len,enable); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1270 |  | 
 | 1271 |               if (len) | 
 | 1272 |                 { | 
 | 1273 |                   skb = dev_alloc_skb (len + 1); | 
 | 1274 |                   if (skb) | 
 | 1275 |                     { | 
 | 1276 |                       skb_reserve (skb, 1); | 
 | 1277 |  | 
 | 1278 |                       skb_put (skb, len); | 
| Arnaldo Carvalho de Melo | 27d7ff4 | 2007-03-31 11:55:19 -0300 | [diff] [blame] | 1279 |                       skb_copy_to_linear_data(skb, self->rx_bufs[self->rxs], | 
 | 1280 | 					      len); | 
| Alexander Beregalov | 216c32d | 2009-01-08 16:42:08 -0800 | [diff] [blame] | 1281 |                       self->netdev->stats.rx_packets++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1282 |                       skb->dev = self->netdev; | 
| Arnaldo Carvalho de Melo | 459a98e | 2007-03-19 15:30:44 -0700 | [diff] [blame] | 1283 |                       skb_reset_mac_header(skb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1284 |                       skb->protocol = htons (ETH_P_IRDA); | 
 | 1285 |                     } | 
 | 1286 |                   else | 
 | 1287 |                     { | 
 | 1288 |                       printk (KERN_INFO | 
 | 1289 |                               "%s(), memory squeeze, dropping frame.\n", | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1290 | 			      __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1291 |                     } | 
 | 1292 |                 } | 
 | 1293 |             } | 
 | 1294 |           else | 
 | 1295 |             { | 
 | 1296 |             /* TODO: =========================================== */ | 
 | 1297 |             /*  if OBOE_CTL_RX_LENGTH, our buffers are too small */ | 
 | 1298 |             /* (MIR or FIR) data is lost. */ | 
 | 1299 |             /* (SIR) data is splitted in several slots. */ | 
 | 1300 |             /* we have to join all the received buffers received */ | 
 | 1301 |             /*in a large buffer before checking CRC. */ | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1302 |             IRDA_DEBUG (0, "%s.err:%x(%x)\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1303 |                 ,len,self->ring->rx[self->rxs].control); | 
 | 1304 |             } | 
 | 1305 |  | 
 | 1306 |           self->ring->rx[self->rxs].len = 0x0; | 
 | 1307 |           self->ring->rx[self->rxs].control = OBOE_CTL_RX_HW_OWNS; | 
 | 1308 |  | 
 | 1309 |           self->rxs++; | 
 | 1310 |           self->rxs %= RX_SLOTS; | 
 | 1311 |  | 
 | 1312 |           if (skb) | 
 | 1313 |               netif_rx (skb); | 
 | 1314 |  | 
 | 1315 |         } | 
 | 1316 |     } | 
 | 1317 |  | 
 | 1318 |   if (irqstat & OBOE_INT_TXUNDER) | 
 | 1319 |     { | 
 | 1320 |       printk (KERN_WARNING DRIVER_NAME ": tx fifo underflow\n"); | 
 | 1321 |     } | 
 | 1322 |   if (irqstat & OBOE_INT_RXOVER) | 
 | 1323 |     { | 
 | 1324 |       printk (KERN_WARNING DRIVER_NAME ": rx fifo overflow\n"); | 
 | 1325 |     } | 
 | 1326 | /* This must be useful for something... */ | 
 | 1327 |   if (irqstat & OBOE_INT_SIP) | 
 | 1328 |     { | 
 | 1329 |       self->int_sip++; | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1330 |       IRDA_DEBUG (1, "%s.sip:%x(%x)%x\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1331 | 	      ,self->int_sip,irqstat,self->txpending); | 
 | 1332 |     } | 
 | 1333 |   return IRQ_HANDLED; | 
 | 1334 | } | 
 | 1335 |  | 
 | 1336 |  | 
 | 1337 | static int | 
 | 1338 | toshoboe_net_open (struct net_device *dev) | 
 | 1339 | { | 
 | 1340 |   struct toshoboe_cb *self; | 
 | 1341 |   unsigned long flags; | 
| Jeff Garzik | 15e541f | 2006-10-10 01:40:55 -0400 | [diff] [blame] | 1342 |   int rc; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1343 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1344 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1345 |  | 
| Jeff Garzik | 15e541f | 2006-10-10 01:40:55 -0400 | [diff] [blame] | 1346 |   self = netdev_priv(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1347 |  | 
 | 1348 |   if (self->async) | 
 | 1349 |     return -EBUSY; | 
 | 1350 |  | 
 | 1351 |   if (self->stopped) | 
 | 1352 |     return 0; | 
 | 1353 |  | 
| Jeff Garzik | 15e541f | 2006-10-10 01:40:55 -0400 | [diff] [blame] | 1354 |   rc = request_irq (self->io.irq, toshoboe_interrupt, | 
 | 1355 |                     IRQF_SHARED | IRQF_DISABLED, dev->name, self); | 
 | 1356 |   if (rc) | 
 | 1357 |   	return rc; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1358 |  | 
 | 1359 |   spin_lock_irqsave(&self->spinlock, flags); | 
 | 1360 |   toshoboe_startchip (self); | 
 | 1361 |   spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1362 |  | 
 | 1363 |   /* Ready to play! */ | 
 | 1364 |   netif_start_queue(dev); | 
 | 1365 |  | 
 | 1366 |   /* | 
 | 1367 |    * Open new IrLAP layer instance, now that everything should be | 
 | 1368 |    * initialized properly | 
 | 1369 |    */ | 
 | 1370 |   self->irlap = irlap_open (dev, &self->qos, driver_name); | 
 | 1371 |  | 
 | 1372 |   self->irdad = 1; | 
 | 1373 |  | 
 | 1374 |   return 0; | 
 | 1375 | } | 
 | 1376 |  | 
 | 1377 | static int | 
 | 1378 | toshoboe_net_close (struct net_device *dev) | 
 | 1379 | { | 
 | 1380 |   struct toshoboe_cb *self; | 
 | 1381 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1382 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1383 |  | 
 | 1384 |   IRDA_ASSERT (dev != NULL, return -1; ); | 
| Wang Chen | 4cf1653 | 2008-11-12 23:38:14 -0800 | [diff] [blame] | 1385 |   self = netdev_priv(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1386 |  | 
 | 1387 |   /* Stop device */ | 
 | 1388 |   netif_stop_queue(dev); | 
 | 1389 |  | 
 | 1390 |   /* Stop and remove instance of IrLAP */ | 
 | 1391 |   if (self->irlap) | 
 | 1392 |     irlap_close (self->irlap); | 
 | 1393 |   self->irlap = NULL; | 
 | 1394 |  | 
 | 1395 |   self->irdad = 0; | 
 | 1396 |  | 
 | 1397 |   free_irq (self->io.irq, (void *) self); | 
 | 1398 |  | 
 | 1399 |   if (!self->stopped) | 
 | 1400 |     { | 
 | 1401 |       toshoboe_stopchip (self); | 
 | 1402 |     } | 
 | 1403 |  | 
 | 1404 |   return 0; | 
 | 1405 | } | 
 | 1406 |  | 
 | 1407 | /* | 
 | 1408 |  * Function toshoboe_net_ioctl (dev, rq, cmd) | 
 | 1409 |  * | 
 | 1410 |  *    Process IOCTL commands for this device | 
 | 1411 |  * | 
 | 1412 |  */ | 
 | 1413 | static int | 
 | 1414 | toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) | 
 | 1415 | { | 
 | 1416 |   struct if_irda_req *irq = (struct if_irda_req *) rq; | 
 | 1417 |   struct toshoboe_cb *self; | 
 | 1418 |   unsigned long flags; | 
 | 1419 |   int ret = 0; | 
 | 1420 |  | 
 | 1421 |   IRDA_ASSERT (dev != NULL, return -1; ); | 
 | 1422 |  | 
| Wang Chen | 4cf1653 | 2008-11-12 23:38:14 -0800 | [diff] [blame] | 1423 |   self = netdev_priv(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1424 |  | 
 | 1425 |   IRDA_ASSERT (self != NULL, return -1; ); | 
 | 1426 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1427 |   IRDA_DEBUG (5, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1428 |  | 
 | 1429 |   /* Disable interrupts & save flags */ | 
 | 1430 |   spin_lock_irqsave(&self->spinlock, flags); | 
 | 1431 |  | 
 | 1432 |   switch (cmd) | 
 | 1433 |     { | 
 | 1434 |     case SIOCSBANDWIDTH:       /* Set bandwidth */ | 
 | 1435 |       /* This function will also be used by IrLAP to change the | 
 | 1436 |        * speed, so we still must allow for speed change within | 
 | 1437 |        * interrupt context. | 
 | 1438 |        */ | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1439 |       IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1440 |           ,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate ); | 
| Andrew Morton | ac7c98e | 2005-11-08 09:41:13 -0800 | [diff] [blame] | 1441 |       if (!in_interrupt () && !capable (CAP_NET_ADMIN)) { | 
 | 1442 | 	ret = -EPERM; | 
 | 1443 | 	goto out; | 
 | 1444 |       } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1445 |  | 
 | 1446 |       /* self->speed=irq->ifr_baudrate; */ | 
 | 1447 |       /* toshoboe_setbaud(self); */ | 
 | 1448 |       /* Just change speed once - inserted by Paul Bristow */ | 
 | 1449 |       self->new_speed = irq->ifr_baudrate; | 
 | 1450 |       break; | 
 | 1451 |     case SIOCSMEDIABUSY:       /* Set media busy */ | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1452 |       IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1453 |           ,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) ); | 
| Andrew Morton | ac7c98e | 2005-11-08 09:41:13 -0800 | [diff] [blame] | 1454 |       if (!capable (CAP_NET_ADMIN)) { | 
 | 1455 | 	ret = -EPERM; | 
 | 1456 | 	goto out; | 
 | 1457 |       } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1458 |       irda_device_set_media_busy (self->netdev, TRUE); | 
 | 1459 |       break; | 
 | 1460 |     case SIOCGRECEIVING:       /* Check if we are receiving right now */ | 
 | 1461 |       irq->ifr_receiving = (INB (OBOE_STATUS) & OBOE_STATUS_RXBUSY) ? 1 : 0; | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1462 |       IRDA_DEBUG (3, "%s(RECEIVING), %s, (%X/%x)\n", __func__ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1463 |           ,dev->name, INB (OBOE_STATUS), irq->ifr_receiving ); | 
 | 1464 |       break; | 
 | 1465 |     default: | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1466 |       IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1467 |       ret = -EOPNOTSUPP; | 
 | 1468 |     } | 
| Andrew Morton | ac7c98e | 2005-11-08 09:41:13 -0800 | [diff] [blame] | 1469 | out: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1470 |   spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1471 |   return ret; | 
 | 1472 |  | 
 | 1473 | } | 
 | 1474 |  | 
 | 1475 | MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver"); | 
 | 1476 | MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>"); | 
 | 1477 | MODULE_LICENSE("GPL"); | 
 | 1478 |  | 
 | 1479 | module_param (max_baud, int, 0); | 
 | 1480 | MODULE_PARM_DESC(max_baud, "Maximum baud rate"); | 
 | 1481 |  | 
 | 1482 | #ifdef USE_PROBE | 
 | 1483 | module_param (do_probe, bool, 0); | 
 | 1484 | MODULE_PARM_DESC(do_probe, "Enable/disable chip probing and self-test"); | 
 | 1485 | #endif | 
 | 1486 |  | 
 | 1487 | static void | 
 | 1488 | toshoboe_close (struct pci_dev *pci_dev) | 
 | 1489 | { | 
 | 1490 |   int i; | 
 | 1491 |   struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev); | 
 | 1492 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1493 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1494 |  | 
 | 1495 |   IRDA_ASSERT (self != NULL, return; ); | 
 | 1496 |  | 
 | 1497 |   if (!self->stopped) | 
 | 1498 |     { | 
 | 1499 |       toshoboe_stopchip (self); | 
 | 1500 |     } | 
 | 1501 |  | 
 | 1502 |   release_region (self->io.fir_base, self->io.fir_ext); | 
 | 1503 |  | 
 | 1504 |   for (i = 0; i < TX_SLOTS; ++i) | 
 | 1505 |     { | 
 | 1506 |       kfree (self->tx_bufs[i]); | 
 | 1507 |       self->tx_bufs[i] = NULL; | 
 | 1508 |     } | 
 | 1509 |  | 
 | 1510 |   for (i = 0; i < RX_SLOTS; ++i) | 
 | 1511 |     { | 
 | 1512 |       kfree (self->rx_bufs[i]); | 
 | 1513 |       self->rx_bufs[i] = NULL; | 
 | 1514 |     } | 
 | 1515 |  | 
 | 1516 |   unregister_netdev(self->netdev); | 
 | 1517 |  | 
 | 1518 |   kfree (self->ringbuf); | 
 | 1519 |   self->ringbuf = NULL; | 
 | 1520 |   self->ring = NULL; | 
 | 1521 |  | 
 | 1522 |   free_netdev(self->netdev); | 
 | 1523 | } | 
 | 1524 |  | 
| Stephen Hemminger | ddec2c8 | 2009-03-26 15:11:22 +0000 | [diff] [blame] | 1525 | static const struct net_device_ops toshoboe_netdev_ops = { | 
 | 1526 | 	.ndo_open	= toshoboe_net_open, | 
 | 1527 | 	.ndo_stop	= toshoboe_net_close, | 
 | 1528 | 	.ndo_start_xmit	= toshoboe_hard_xmit, | 
 | 1529 | 	.ndo_do_ioctl	= toshoboe_net_ioctl, | 
 | 1530 | }; | 
 | 1531 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1532 | static int | 
 | 1533 | toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) | 
 | 1534 | { | 
 | 1535 |   struct toshoboe_cb *self; | 
 | 1536 |   struct net_device *dev; | 
 | 1537 |   int i = 0; | 
 | 1538 |   int ok = 0; | 
 | 1539 |   int err; | 
 | 1540 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1541 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1542 |  | 
 | 1543 |   if ((err=pci_enable_device(pci_dev))) | 
 | 1544 |     return err; | 
 | 1545 |  | 
 | 1546 |   dev = alloc_irdadev(sizeof (struct toshoboe_cb)); | 
 | 1547 |   if (dev == NULL) | 
 | 1548 |     { | 
 | 1549 |       printk (KERN_ERR DRIVER_NAME ": can't allocate memory for " | 
 | 1550 |               "IrDA control block\n"); | 
 | 1551 |       return -ENOMEM; | 
 | 1552 |     } | 
 | 1553 |  | 
| Wang Chen | 4cf1653 | 2008-11-12 23:38:14 -0800 | [diff] [blame] | 1554 |   self = netdev_priv(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1555 |   self->netdev = dev; | 
 | 1556 |   self->pdev = pci_dev; | 
 | 1557 |   self->base = pci_resource_start(pci_dev,0); | 
 | 1558 |  | 
 | 1559 |   self->io.fir_base = self->base; | 
 | 1560 |   self->io.fir_ext = OBOE_IO_EXTENT; | 
 | 1561 |   self->io.irq = pci_dev->irq; | 
| Thomas Gleixner | 1fb9df5 | 2006-07-01 19:29:39 -0700 | [diff] [blame] | 1562 |   self->io.irqflags = IRQF_SHARED | IRQF_DISABLED; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1563 |  | 
 | 1564 |   self->speed = self->io.speed = 9600; | 
 | 1565 |   self->async = 0; | 
 | 1566 |  | 
 | 1567 |   /* Lock the port that we need */ | 
 | 1568 |   if (NULL==request_region (self->io.fir_base, self->io.fir_ext, driver_name)) | 
 | 1569 |     { | 
 | 1570 |       printk (KERN_ERR DRIVER_NAME ": can't get iobase of 0x%03x\n" | 
 | 1571 | 	      ,self->io.fir_base); | 
 | 1572 |       err = -EBUSY; | 
 | 1573 |       goto freeself; | 
 | 1574 |     } | 
 | 1575 |  | 
 | 1576 |   spin_lock_init(&self->spinlock); | 
 | 1577 |  | 
 | 1578 |   irda_init_max_qos_capabilies (&self->qos); | 
 | 1579 |   self->qos.baud_rate.bits = 0; | 
 | 1580 |  | 
 | 1581 |   if (max_baud >= 2400) | 
 | 1582 |     self->qos.baud_rate.bits |= IR_2400; | 
 | 1583 |   /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */ | 
 | 1584 |   if (max_baud >= 9600) | 
 | 1585 |     self->qos.baud_rate.bits |= IR_9600; | 
 | 1586 |   if (max_baud >= 19200) | 
 | 1587 |     self->qos.baud_rate.bits |= IR_19200; | 
 | 1588 |   if (max_baud >= 115200) | 
 | 1589 |     self->qos.baud_rate.bits |= IR_115200; | 
 | 1590 | #ifdef USE_MIR | 
 | 1591 |   if (max_baud >= 1152000) | 
 | 1592 |     { | 
 | 1593 |       self->qos.baud_rate.bits |= IR_1152000; | 
 | 1594 |     } | 
 | 1595 | #endif | 
 | 1596 |   if (max_baud >= 4000000) | 
 | 1597 |     { | 
 | 1598 |       self->qos.baud_rate.bits |= (IR_4000000 << 8); | 
 | 1599 |     } | 
 | 1600 |  | 
 | 1601 |   /*FIXME: work this out... */ | 
 | 1602 |   self->qos.min_turn_time.bits = 0xff; | 
 | 1603 |  | 
 | 1604 |   irda_qos_bits_to_value (&self->qos); | 
 | 1605 |  | 
 | 1606 |   /* Allocate twice the size to guarantee alignment */ | 
| Robert P. J. Day | 5cbded5 | 2006-12-13 00:35:56 -0800 | [diff] [blame] | 1607 |   self->ringbuf = kmalloc(OBOE_RING_LEN << 1, GFP_KERNEL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1608 |   if (!self->ringbuf) | 
 | 1609 |     { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1610 |       err = -ENOMEM; | 
 | 1611 |       goto freeregion; | 
 | 1612 |     } | 
 | 1613 |  | 
 | 1614 | #if (BITS_PER_LONG == 64) | 
 | 1615 | #error broken on 64-bit:  casts pointer to 32-bit, and then back to pointer. | 
 | 1616 | #endif | 
 | 1617 |  | 
 | 1618 |   /*We need to align the taskfile on a taskfile size boundary */ | 
 | 1619 |   { | 
 | 1620 |     unsigned long addr; | 
 | 1621 |  | 
 | 1622 |     addr = (__u32) self->ringbuf; | 
 | 1623 |     addr &= ~(OBOE_RING_LEN - 1); | 
 | 1624 |     addr += OBOE_RING_LEN; | 
 | 1625 |     self->ring = (struct OboeRing *) addr; | 
 | 1626 |   } | 
 | 1627 |  | 
 | 1628 |   memset (self->ring, 0, OBOE_RING_LEN); | 
 | 1629 |   self->io.mem_base = (__u32) self->ring; | 
 | 1630 |  | 
 | 1631 |   ok = 1; | 
 | 1632 |   for (i = 0; i < TX_SLOTS; ++i) | 
 | 1633 |     { | 
 | 1634 |       self->tx_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL); | 
 | 1635 |       if (!self->tx_bufs[i]) | 
 | 1636 |         ok = 0; | 
 | 1637 |     } | 
 | 1638 |  | 
 | 1639 |   for (i = 0; i < RX_SLOTS; ++i) | 
 | 1640 |     { | 
 | 1641 |       self->rx_bufs[i] = kmalloc (RX_BUF_SZ, GFP_KERNEL); | 
 | 1642 |       if (!self->rx_bufs[i]) | 
 | 1643 |         ok = 0; | 
 | 1644 |     } | 
 | 1645 |  | 
 | 1646 |   if (!ok) | 
 | 1647 |     { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1648 |       err = -ENOMEM; | 
 | 1649 |       goto freebufs; | 
 | 1650 |     } | 
 | 1651 |  | 
 | 1652 |  | 
 | 1653 | #ifdef USE_PROBE | 
 | 1654 |   if (do_probe) | 
 | 1655 |     if (!toshoboe_probe (self)) | 
 | 1656 |       { | 
 | 1657 |         err = -ENODEV; | 
 | 1658 |         goto freebufs; | 
 | 1659 |       } | 
 | 1660 | #endif | 
 | 1661 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1662 |   SET_NETDEV_DEV(dev, &pci_dev->dev); | 
| Stephen Hemminger | ddec2c8 | 2009-03-26 15:11:22 +0000 | [diff] [blame] | 1663 |   dev->netdev_ops = &toshoboe_netdev_ops; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1664 |  | 
 | 1665 |   err = register_netdev(dev); | 
 | 1666 |   if (err) | 
 | 1667 |     { | 
 | 1668 |       printk (KERN_ERR DRIVER_NAME ": register_netdev() failed\n"); | 
 | 1669 |       err = -ENOMEM; | 
 | 1670 |       goto freebufs; | 
 | 1671 |     } | 
 | 1672 |   printk (KERN_INFO "IrDA: Registered device %s\n", dev->name); | 
 | 1673 |  | 
 | 1674 |   pci_set_drvdata(pci_dev,self); | 
 | 1675 |  | 
| Adrian Bunk | d4c3c07 | 2008-06-10 22:48:08 -0700 | [diff] [blame] | 1676 |   printk (KERN_INFO DRIVER_NAME ": Using multiple tasks\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1677 |  | 
 | 1678 |   return 0; | 
 | 1679 |  | 
 | 1680 | freebufs: | 
 | 1681 |   for (i = 0; i < TX_SLOTS; ++i) | 
| Jesper Juhl | b4558ea | 2005-10-28 16:53:13 -0400 | [diff] [blame] | 1682 |     kfree (self->tx_bufs[i]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1683 |   for (i = 0; i < RX_SLOTS; ++i) | 
| Jesper Juhl | b4558ea | 2005-10-28 16:53:13 -0400 | [diff] [blame] | 1684 |     kfree (self->rx_bufs[i]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1685 |   kfree(self->ringbuf); | 
 | 1686 |  | 
 | 1687 | freeregion: | 
 | 1688 |   release_region (self->io.fir_base, self->io.fir_ext); | 
 | 1689 |  | 
 | 1690 | freeself: | 
 | 1691 |   free_netdev(dev); | 
 | 1692 |  | 
 | 1693 |   return err; | 
 | 1694 | } | 
 | 1695 |  | 
 | 1696 | static int | 
 | 1697 | toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap) | 
 | 1698 | { | 
 | 1699 |   struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev); | 
 | 1700 |   unsigned long flags; | 
 | 1701 |   int i = 10; | 
 | 1702 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1703 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1704 |  | 
 | 1705 |   if (!self || self->stopped) | 
 | 1706 |     return 0; | 
 | 1707 |  | 
 | 1708 |   if ((!self->irdad) && (!self->async)) | 
 | 1709 |     return 0; | 
 | 1710 |  | 
 | 1711 | /* Flush all packets */ | 
 | 1712 |   while ((i--) && (self->txpending)) | 
| Arnd Bergmann | 32fd32a | 2012-04-20 10:56:14 +0000 | [diff] [blame] | 1713 |     msleep(10); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1714 |  | 
 | 1715 |   spin_lock_irqsave(&self->spinlock, flags); | 
 | 1716 |  | 
 | 1717 |   toshoboe_stopchip (self); | 
 | 1718 |   self->stopped = 1; | 
 | 1719 |   self->txpending = 0; | 
 | 1720 |  | 
 | 1721 |   spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1722 |   return 0; | 
 | 1723 | } | 
 | 1724 |  | 
 | 1725 | static int | 
 | 1726 | toshoboe_wakeup (struct pci_dev *pci_dev) | 
 | 1727 | { | 
 | 1728 |   struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev); | 
 | 1729 |   unsigned long flags; | 
 | 1730 |  | 
| Harvey Harrison | a97a6f1 | 2008-07-30 17:20:18 -0700 | [diff] [blame] | 1731 |   IRDA_DEBUG (4, "%s()\n", __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1732 |  | 
 | 1733 |   if (!self || !self->stopped) | 
 | 1734 |     return 0; | 
 | 1735 |  | 
 | 1736 |   if ((!self->irdad) && (!self->async)) | 
 | 1737 |     return 0; | 
 | 1738 |  | 
 | 1739 |   spin_lock_irqsave(&self->spinlock, flags); | 
 | 1740 |  | 
 | 1741 |   toshoboe_startchip (self); | 
 | 1742 |   self->stopped = 0; | 
 | 1743 |  | 
 | 1744 |   netif_wake_queue(self->netdev); | 
 | 1745 |   spin_unlock_irqrestore(&self->spinlock, flags); | 
 | 1746 |   return 0; | 
 | 1747 | } | 
 | 1748 |  | 
 | 1749 | static struct pci_driver donauboe_pci_driver = { | 
 | 1750 | 	.name		= "donauboe", | 
 | 1751 | 	.id_table	= toshoboe_pci_tbl, | 
 | 1752 | 	.probe		= toshoboe_open, | 
 | 1753 | 	.remove		= toshoboe_close, | 
 | 1754 | 	.suspend	= toshoboe_gotosleep, | 
 | 1755 | 	.resume		= toshoboe_wakeup  | 
 | 1756 | }; | 
 | 1757 |  | 
 | 1758 | static int __init | 
 | 1759 | donauboe_init (void) | 
 | 1760 | { | 
| Christophe Lucas | a85d771 | 2006-03-20 19:00:27 -0800 | [diff] [blame] | 1761 |   return pci_register_driver(&donauboe_pci_driver); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1762 | } | 
 | 1763 |  | 
 | 1764 | static void __exit | 
 | 1765 | donauboe_cleanup (void) | 
 | 1766 | { | 
 | 1767 |   pci_unregister_driver(&donauboe_pci_driver); | 
 | 1768 | } | 
 | 1769 |  | 
 | 1770 | module_init(donauboe_init); | 
 | 1771 | module_exit(donauboe_cleanup); |