📄 toshoboe.c
字号:
/********************************************************************* * * Filename: toshoboe.c * Version: 0.1 * Description: Driver for the Toshiba OBOE (or type-O or 700 or 701) * FIR Chipset. * Status: Experimental. * Author: James McKenzie <james@fishsoup.dhs.org> * Created at: Sat May 8 12:35:27 1999 * Modified: Paul Bristow <paul.bristow@technologist.com> * Modified: Mon Nov 11 19:10:05 1999 * * Copyright (c) 1999-2000 James McKenzie, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Neither James McKenzie nor Cambridge University admit liability nor * provide warranty for any of this software. This material is * provided "AS-IS" and at no charge. * * Applicable Models : Libretto 100CT. and many more * Toshiba refers to this chip as the type-O IR port. * ********************************************************************//* This driver is experimental, I have only three ir devices *//* an olivetti notebook which doesn't have FIR, a toshiba libretto, and *//* an hp printer, this works fine at 4MBPS with my HP printer */static char *rcsid = "$Id: toshoboe.c,v 1.91 1999/06/29 14:21:06 root Exp $";/* Define this to have only one frame in the XMIT or RECV queue *//* Toshiba's drivers do this, but it disables back to back tansfers *//* I think that the chip may have some problems certainly, I have *//* seen it jump over tasks in the taskfile->xmit with this turned on */#define ONETASK /* To adjust the number of tasks in use edit toshoboe.h *//* Define this to enable FIR and MIR support */#define ENABLE_FAST/* Size of IO window */#define CHIP_IO_EXTENT 0x1f/* Transmit and receive buffer sizes, adjust at your peril */#define RX_BUF_SZ 4196#define TX_BUF_SZ 4196/* No user servicable parts below here */#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/rtnetlink.h>#include <asm/system.h>#include <asm/io.h>#include <net/irda/wrapper.h>#include <net/irda/irda.h>#include <net/irda/irmod.h>#include <net/irda/irlap_frame.h>#include <net/irda/irda_device.h>#include <linux/pm.h>#include <net/irda/toshoboe.h>#define PCI_DEVICE_ID_FIR701b 0x0d01static struct pci_device_id toshoboe_pci_tbl[] __initdata = { { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701b, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */};MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl);static const char *driver_name = "toshoboe";static int max_baud = 4000000;/* Shutdown the chip and point the taskfile reg somewhere else */static voidtoshoboe_stopchip (struct toshoboe_cb *self){ IRDA_DEBUG (4, __FUNCTION__ "()\n"); outb_p (0x0e, OBOE_REG_11); outb_p (0x00, OBOE_RST); outb_p (0x3f, OBOE_TFP2); /*Write the taskfile address */ outb_p (0xff, OBOE_TFP1); outb_p (0xff, OBOE_TFP0); outb_p (0x0f, OBOE_REG_1B); outb_p (0xff, OBOE_REG_1A); outb_p (0x00, OBOE_ISR); /*FIXME: should i do this to disbale ints */ outb_p (0x80, OBOE_RST); outb_p (0xe, OBOE_LOCK);}/*Set the baud rate */static voidtoshoboe_setbaud (struct toshoboe_cb *self, int baud){ unsigned long flags; IRDA_DEBUG (4, __FUNCTION__ "()\n"); printk (KERN_WARNING "ToshOboe: setting baud to %d\n", baud); save_flags (flags); cli (); switch (baud) { case 2400: outb_p (OBOE_PMDL_SIR, OBOE_PMDL); outb_p (OBOE_SMDL_SIR, OBOE_SMDL); outb_p (0xbf, OBOE_UDIV); break; case 4800: outb_p (OBOE_PMDL_SIR, OBOE_PMDL); outb_p (OBOE_SMDL_SIR, OBOE_SMDL); outb_p (0x5f, OBOE_UDIV); break; case 9600: outb_p (OBOE_PMDL_SIR, OBOE_PMDL); outb_p (OBOE_SMDL_SIR, OBOE_SMDL); outb_p (0x2f, OBOE_UDIV); break; case 19200: outb_p (OBOE_PMDL_SIR, OBOE_PMDL); outb_p (OBOE_SMDL_SIR, OBOE_SMDL); outb_p (0x17, OBOE_UDIV); break; case 38400: outb_p (OBOE_PMDL_SIR, OBOE_PMDL); outb_p (OBOE_SMDL_SIR, OBOE_SMDL); outb_p (0xb, OBOE_UDIV); break; case 57600: outb_p (OBOE_PMDL_SIR, OBOE_PMDL); outb_p (OBOE_SMDL_SIR, OBOE_SMDL); outb_p (0x7, OBOE_UDIV); break; case 115200: outb_p (OBOE_PMDL_SIR, OBOE_PMDL); outb_p (OBOE_SMDL_SIR, OBOE_SMDL); outb_p (0x3, OBOE_UDIV); break; case 1152000: outb_p (OBOE_PMDL_MIR, OBOE_PMDL); outb_p (OBOE_SMDL_MIR, OBOE_SMDL); outb_p (0x1, OBOE_UDIV); break; case 4000000: outb_p (OBOE_PMDL_FIR, OBOE_PMDL); outb_p (OBOE_SMDL_FIR, OBOE_SMDL); outb_p (0x0, OBOE_UDIV); break; } restore_flags (flags); outb_p (0x00, OBOE_RST); outb_p (0x80, OBOE_RST); outb_p (0x01, OBOE_REG_9); self->io.speed = baud;}/* Wake the chip up and get it looking at the taskfile */static voidtoshoboe_startchip (struct toshoboe_cb *self){ __u32 physaddr; IRDA_DEBUG (4, __FUNCTION__ "()\n"); outb_p (0, OBOE_LOCK); outb_p (0, OBOE_RST); outb_p (OBOE_NTR_VAL, OBOE_NTR); outb_p (0xf0, OBOE_REG_D); outb_p (0xff, OBOE_ISR); outb_p (0x0f, OBOE_REG_1B); outb_p (0xff, OBOE_REG_1A); physaddr = virt_to_bus (self->taskfile); outb_p ((physaddr >> 0x0a) & 0xff, OBOE_TFP0); outb_p ((physaddr >> 0x12) & 0xff, OBOE_TFP1); outb_p ((physaddr >> 0x1a) & 0x3f, OBOE_TFP2); outb_p (0x0e, OBOE_REG_11); outb_p (0x80, OBOE_RST); toshoboe_setbaud (self, 9600);}/*Let the chip look at memory */static voidtoshoboe_enablebm (struct toshoboe_cb *self){ IRDA_DEBUG (4, __FUNCTION__ "()\n"); pci_set_master (self->pdev);}/*Don't let the chip look at memory */static voidtoshoboe_disablebm (struct toshoboe_cb *self){ __u8 command; IRDA_DEBUG (4, __FUNCTION__ "()\n"); pci_read_config_byte (self->pdev, PCI_COMMAND, &command); command &= ~PCI_COMMAND_MASTER; pci_write_config_byte (self->pdev, PCI_COMMAND, command);}/*setup the taskfile */static voidtoshoboe_initbuffs (struct toshoboe_cb *self){ int i; unsigned long flags; IRDA_DEBUG (4, __FUNCTION__ "()\n"); save_flags (flags); cli (); for (i = 0; i < TX_SLOTS; ++i) { self->taskfile->xmit[i].len = 0; self->taskfile->xmit[i].control = 0x00; self->taskfile->xmit[i].buffer = virt_to_bus (self->xmit_bufs[i]); } for (i = 0; i < RX_SLOTS; ++i) { self->taskfile->recv[i].len = 0; self->taskfile->recv[i].control = 0x83; self->taskfile->recv[i].buffer = virt_to_bus (self->recv_bufs[i]); } restore_flags (flags);}/*Transmit something */static inttoshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev){ struct toshoboe_cb *self; __s32 speed; int mtt, len; self = (struct toshoboe_cb *) dev->priv; ASSERT (self != NULL, return 0; ); /* Check if we need to change the speed */ speed = irda_get_next_speed(skb); if ((speed != self->io.speed) && (speed != -1)) { /* Check for empty frame */ if (!skb->len) { toshoboe_setbaud(self, speed); dev_kfree_skb(skb); return 0; } else self->new_speed = speed; } netif_stop_queue(dev); if (self->stopped) { dev_kfree_skb(skb); return 0; }#ifdef ONETASK if (self->txpending) return -EBUSY; self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET; self->txs &= 0x3f;#endif if (self->taskfile->xmit[self->txs].control) return -EBUSY; if (inb_p (OBOE_RST) & OBOE_RST_WRAP) { len = async_wrap_skb (skb, self->xmit_bufs[self->txs], TX_BUF_SZ); } else { len = skb->len; memcpy (self->xmit_bufs[self->txs], skb->data, len); } self->taskfile->xmit[self->txs].len = len & 0x0fff; outb_p (0, OBOE_RST); outb_p (0x1e, OBOE_REG_11); self->taskfile->xmit[self->txs].control = 0x84; mtt = irda_get_mtt (skb); if (mtt) udelay (mtt); self->txpending++; /*FIXME: ask about busy,media_busy stuff, for the moment */ /*busy means can't queue any more */#ifndef ONETASK if (self->txpending != TX_SLOTS) { netif_wake_queue(dev); }#endif outb_p (0x80, OBOE_RST); outb_p (1, OBOE_REG_9); self->txs++; self->txs %= TX_SLOTS; dev_kfree_skb (skb); return 0;}/*interrupt handler */static voidtoshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs){ struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id; __u8 irqstat; struct sk_buff *skb; if (self == NULL) { printk (KERN_WARNING "%s: irq %d for unknown device.\n", driver_name, irq); return; } IRDA_DEBUG (4, __FUNCTION__ "()\n"); irqstat = inb_p (OBOE_ISR);/* woz it us */ if (!(irqstat & 0xf8)) return; outb_p (irqstat, OBOE_ISR); /*Acknologede it *//* Txdone */ if (irqstat & OBOE_ISR_TXDONE) { self->txpending--; self->stats.tx_packets++; if (self->new_speed) { toshoboe_setbaud(self, self->new_speed); self->new_speed = 0; } /* Tell network layer that we want more frames */ netif_wake_queue(self->netdev); } if (irqstat & OBOE_ISR_RXDONE) {#ifdef ONETASK self->rxs = inb_p (OBOE_RCVT); self->rxs += (RX_SLOTS - 1); self->rxs %= RX_SLOTS;#else while (self->taskfile->recv[self->rxs].control == 0)#endif { int len = self->taskfile->recv[self->rxs].len; if (len > 2) len -= 2; skb = dev_alloc_skb (len + 1); if (skb) { skb_reserve (skb, 1); skb_put (skb, len); memcpy (skb->data, self->recv_bufs[self->rxs], len); self->stats.rx_packets++; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons (ETH_P_IRDA); } else { printk (KERN_INFO __FUNCTION__ "(), memory squeeze, dropping frame.\n"); } self->taskfile->recv[self->rxs].control = 0x83; self->taskfile->recv[self->rxs].len = 0x0; self->rxs++; self->rxs %= RX_SLOTS; if (skb) netif_rx (skb); } } if (irqstat & OBOE_ISR_20) { printk (KERN_WARNING "Oboe_irq: 20\n"); } if (irqstat & OBOE_ISR_10) { printk (KERN_WARNING "Oboe_irq: 10\n"); } if (irqstat & 0x8) { /*FIXME: I think this is a TX or RX error of some sort */ self->stats.tx_errors++; self->stats.rx_errors++; }}static inttoshoboe_net_init (struct net_device *dev){ IRDA_DEBUG (4, __FUNCTION__ "()\n"); /* Setup to be a normal IrDA network device driver */ irda_device_setup (dev); /* Insert overrides below this line! */ return 0;}static void toshoboe_initptrs (struct toshoboe_cb *self){ unsigned long flags; save_flags (flags); cli ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -