📄 w83977af_ir.c
字号:
/********************************************************************* * * Filename: w83977af_ir.c * Version: 1.0 * Description: FIR driver for the Winbond W83977AF Super I/O chip * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 * Modified at: Fri Jan 28 12:10:59 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> * Copyright (c) 1998-1999 Rebel.com * * 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 Paul VanderSpek nor Rebel.com admit liability nor provide * warranty for any of this software. This material is provided "AS-IS" * and at no charge. * * If you find bugs in this file, its very likely that the same bug * will also be in pc87108.c since the implementations are quite * similar. * * Notice that all functions that needs to access the chip in _any_ * way, must save BSR register on entry, and restore it on exit. * It is _very_ important to follow this policy! * * __u8 bank; * * bank = inb( iobase+BSR); * * do_your_stuff_here(); * * outb( bank, iobase+BSR); * ********************************************************************/#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/rtnetlink.h>#include <linux/dma-mapping.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <net/irda/irda.h>#include <net/irda/wrapper.h>#include <net/irda/irda_device.h>#include "w83977af.h"#include "w83977af_ir.h"#ifdef CONFIG_ARCH_NETWINDER /* Adjust to NetWinder differences */#undef CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */#define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */#endif#undef CONFIG_USE_INTERNAL_TIMER /* Just cannot make that timer work */#define CONFIG_USE_W977_PNP /* Currently needed */#define PIO_MAX_SPEED 115200 static char *driver_name = "w83977af_ir";static int qos_mtt_bits = 0x07; /* 1 ms or more */#define CHIP_IO_EXTENT 8static unsigned int io[] = { 0x180, ~0, ~0, ~0 };#ifdef CONFIG_ARCH_NETWINDER /* Adjust to NetWinder differences */static unsigned int irq[] = { 6, 0, 0, 0 };#elsestatic unsigned int irq[] = { 11, 0, 0, 0 };#endifstatic unsigned int dma[] = { 1, 0, 0, 0 };static unsigned int efbase[] = { W977_EFIO_BASE, W977_EFIO2_BASE };static unsigned int efio = W977_EFIO_BASE;static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL};/* Some prototypes */static int w83977af_open(int i, unsigned int iobase, unsigned int irq, unsigned int dma);static int w83977af_close(struct w83977af_ir *self);static int w83977af_probe(int iobase, int irq, int dma);static int w83977af_dma_receive(struct w83977af_ir *self); static int w83977af_dma_receive_complete(struct w83977af_ir *self);static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev);static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size);static void w83977af_dma_write(struct w83977af_ir *self, int iobase);static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed);static int w83977af_is_receiving(struct w83977af_ir *self);static int w83977af_net_open(struct net_device *dev);static int w83977af_net_close(struct net_device *dev);static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev);/* * Function w83977af_init () * * Initialize chip. Just try to find out how many chips we are dealing with * and where they are */static int __init w83977af_init(void){ int i; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) { if (w83977af_open(i, io[i], irq[i], dma[i]) == 0) return 0; } return -ENODEV;}/* * Function w83977af_cleanup () * * Close all configured chips * */static void __exit w83977af_cleanup(void){ int i; IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); for (i=0; i < ARRAY_SIZE(dev_self); i++) { if (dev_self[i]) w83977af_close(dev_self[i]); }}/* * Function w83977af_open (iobase, irq) * * Open driver instance * */int w83977af_open(int i, unsigned int iobase, unsigned int irq, unsigned int dma){ struct net_device *dev; struct w83977af_ir *self; int err; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); /* Lock the port that we need */ if (!request_region(iobase, CHIP_IO_EXTENT, driver_name)) { IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n", __FUNCTION__ , iobase); return -ENODEV; } if (w83977af_probe(iobase, irq, dma) == -1) { err = -1; goto err_out; } /* * Allocate new instance of the driver */ dev = alloc_irdadev(sizeof(struct w83977af_ir)); if (dev == NULL) { printk( KERN_ERR "IrDA: Can't allocate memory for " "IrDA control block!\n"); err = -ENOMEM; goto err_out; } self = dev->priv; spin_lock_init(&self->lock); /* Initialize IO */ self->io.fir_base = iobase; self->io.irq = irq; self->io.fir_ext = CHIP_IO_EXTENT; self->io.dma = dma; self->io.fifo_size = 32; /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); /* The only value we must override it the baudrate */ /* FIXME: The HP HDLS-1100 does not support 1152000! */ self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); /* The HP HDLS-1100 needs 1 ms according to the specs */ self->qos.min_turn_time.bits = qos_mtt_bits; irda_qos_bits_to_value(&self->qos); /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ self->rx_buff.truesize = 14384; self->tx_buff.truesize = 4000; /* Allocate memory if needed */ self->rx_buff.head = dma_alloc_coherent(NULL, self->rx_buff.truesize, &self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) { err = -ENOMEM; goto err_out1; } memset(self->rx_buff.head, 0, self->rx_buff.truesize); self->tx_buff.head = dma_alloc_coherent(NULL, self->tx_buff.truesize, &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) { err = -ENOMEM; goto err_out2; } memset(self->tx_buff.head, 0, self->tx_buff.truesize); self->rx_buff.in_frame = FALSE; self->rx_buff.state = OUTSIDE_FRAME; self->tx_buff.data = self->tx_buff.head; self->rx_buff.data = self->rx_buff.head; self->netdev = dev; /* Keep track of module usage */ SET_MODULE_OWNER(dev); /* Override the network functions we need to use */ dev->hard_start_xmit = w83977af_hard_xmit; dev->open = w83977af_net_open; dev->stop = w83977af_net_close; dev->do_ioctl = w83977af_net_ioctl; dev->get_stats = w83977af_net_get_stats; err = register_netdev(dev); if (err) { IRDA_ERROR("%s(), register_netdevice() failed!\n", __FUNCTION__); goto err_out3; } IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name); /* Need to store self somewhere */ dev_self[i] = self; return 0;err_out3: dma_free_coherent(NULL, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma);err_out2: dma_free_coherent(NULL, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma);err_out1: free_netdev(dev);err_out: release_region(iobase, CHIP_IO_EXTENT); return err;}/* * Function w83977af_close (self) * * Close driver instance * */static int w83977af_close(struct w83977af_ir *self){ int iobase; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); iobase = self->io.fir_base;#ifdef CONFIG_USE_W977_PNP /* enter PnP configuration mode */ w977_efm_enter(efio); w977_select_device(W977_DEVICE_IR, efio); /* Deactivate device */ w977_write_reg(0x30, 0x00, efio); w977_efm_exit(efio);#endif /* CONFIG_USE_W977_PNP */ /* Remove netdevice */ unregister_netdev(self->netdev); /* Release the PORT that this driver is using */ IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", __FUNCTION__ , self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) dma_free_coherent(NULL, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); if (self->rx_buff.head) dma_free_coherent(NULL, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); free_netdev(self->netdev); return 0;}int w83977af_probe( int iobase, int irq, int dma){ int version; int i; for (i=0; i < 2; i++) { IRDA_DEBUG( 0, "%s()\n", __FUNCTION__ );#ifdef CONFIG_USE_W977_PNP /* Enter PnP configuration mode */ w977_efm_enter(efbase[i]); w977_select_device(W977_DEVICE_IR, efbase[i]); /* Configure PnP port, IRQ, and DMA channel */ w977_write_reg(0x60, (iobase >> 8) & 0xff, efbase[i]); w977_write_reg(0x61, (iobase) & 0xff, efbase[i]); w977_write_reg(0x70, irq, efbase[i]);#ifdef CONFIG_ARCH_NETWINDER /* Netwinder uses 1 higher than Linux */ w977_write_reg(0x74, dma+1, efbase[i]);#else w977_write_reg(0x74, dma, efbase[i]); #endif /*CONFIG_ARCH_NETWINDER */ w977_write_reg(0x75, 0x04, efbase[i]); /* Disable Tx DMA */ /* Set append hardware CRC, enable IR bank selection */ w977_write_reg(0xf0, APEDCRC|ENBNKSEL, efbase[i]); /* Activate device */ w977_write_reg(0x30, 0x01, efbase[i]); w977_efm_exit(efbase[i]);#endif /* CONFIG_USE_W977_PNP */ /* Disable Advanced mode */ switch_bank(iobase, SET2); outb(iobase+2, 0x00); /* Turn on UART (global) interrupts */ switch_bank(iobase, SET0); outb(HCR_EN_IRQ, iobase+HCR); /* Switch to advanced mode */ switch_bank(iobase, SET2); outb(inb(iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1); /* Set default IR-mode */ switch_bank(iobase, SET0); outb(HCR_SIR, iobase+HCR); /* Read the Advanced IR ID */ switch_bank(iobase, SET3); version = inb(iobase+AUID); /* Should be 0x1? */ if (0x10 == (version & 0xf0)) { efio = efbase[i]; /* Set FIFO size to 32 */ switch_bank(iobase, SET2); outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); /* Set FIFO threshold to TX17, RX16 */ switch_bank(iobase, SET0); outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST| UFR_EN_FIFO,iobase+UFR); /* Receiver frame length */ switch_bank(iobase, SET4); outb(2048 & 0xff, iobase+6); outb((2048 >> 8) & 0x1f, iobase+7); /* * Init HP HSDL-1100 transceiver. * * Set IRX_MSL since we have 2 * receive paths IRRX, * and IRRXH. Clear IRSL0D since we want IRSL0 * to * be a input pin used for IRRXH * * IRRX pin 37 connected to receiver * IRTX pin 38 connected to transmitter * FIRRX pin 39 connected to receiver (IRSL0) * CIRRX pin 40 connected to pin 37 */ switch_bank(iobase, SET7); outb(0x40, iobase+7); IRDA_MESSAGE("W83977AF (IR) driver loaded. " "Version: 0x%02x\n", version); return 0; } else { /* Try next extented function register address */ IRDA_DEBUG( 0, "%s(), Wrong chip version", __FUNCTION__ ); } } return -1;}void w83977af_change_speed(struct w83977af_ir *self, __u32 speed){ int ir_mode = HCR_SIR; int iobase; __u8 set; iobase = self->io.fir_base; /* Update accounting for new speed */ self->io.speed = speed; /* Save current bank */ set = inb(iobase+SSR); /* Disable interrupts */ switch_bank(iobase, SET0); outb(0, iobase+ICR); /* Select Set 2 */ switch_bank(iobase, SET2); outb(0x00, iobase+ABHL); switch (speed) { case 9600: outb(0x0c, iobase+ABLL); break; case 19200: outb(0x06, iobase+ABLL); break; case 38400: outb(0x03, iobase+ABLL); break; case 57600: outb(0x02, iobase+ABLL); break; case 115200: outb(0x01, iobase+ABLL); break; case 576000: ir_mode = HCR_MIR_576; IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__ ); break; case 1152000: ir_mode = HCR_MIR_1152; IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__ ); break; case 4000000: ir_mode = HCR_FIR; IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__ ); break; default: ir_mode = HCR_FIR; IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", __FUNCTION__ , speed); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -