📄 ali-ircc.c
字号:
/********************************************************************* * * Filename: ali-ircc.h * Version: 0.5 * Description: Driver for the ALI M1535D and M1543C FIR Controller * Status: Experimental. * Author: Benjamin Kong <benjamin_kong@ali.com.tw> * Created at: 2000/10/16 03:46PM * Modified at: 2001/1/3 02:55PM * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw> * Modified at: 2003/11/6 and support for ALi south-bridge chipsets M1563 * Modified by: Clear Zhang <clear_zhang@ali.com.tw> * * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> * 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. * ********************************************************************/#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/serial_reg.h>#include <linux/dma-mapping.h>#include <linux/platform_device.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <net/irda/wrapper.h>#include <net/irda/irda.h>#include <net/irda/irda_device.h>#include "ali-ircc.h"#define CHIP_IO_EXTENT 8#define BROKEN_DONGLE_ID#define ALI_IRCC_DRIVER_NAME "ali-ircc"/* Power Management */static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state);static int ali_ircc_resume(struct platform_device *dev);static struct platform_driver ali_ircc_driver = { .suspend = ali_ircc_suspend, .resume = ali_ircc_resume, .driver = { .name = ALI_IRCC_DRIVER_NAME, },};/* Module parameters */static int qos_mtt_bits = 0x07; /* 1 ms or more *//* Use BIOS settions by default, but user may supply module parameters */static unsigned int io[] = { ~0, ~0, ~0, ~0 };static unsigned int irq[] = { 0, 0, 0, 0 };static unsigned int dma[] = { 0, 0, 0, 0 };static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info);static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info);static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info);/* These are the currently known ALi sourth-bridge chipsets, the only one difference * is that M1543C doesn't support HP HDSL-3600 */static ali_chip_t chips[] ={ { "M1543", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x43, ali_ircc_probe_53, ali_ircc_init_43 }, { "M1535", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x53, ali_ircc_probe_53, ali_ircc_init_53 }, { "M1563", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x63, ali_ircc_probe_53, ali_ircc_init_53 }, { NULL }};/* Max 4 instances for now */static struct ali_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };/* Dongle Types */static char *dongle_types[] = { "TFDS6000", "HP HSDL-3600", "HP HSDL-1100", "No dongle connected",};/* Some prototypes */static int ali_ircc_open(int i, chipio_t *info);static int ali_ircc_close(struct ali_ircc_cb *self);static int ali_ircc_setup(chipio_t *info);static int ali_ircc_is_receiving(struct ali_ircc_cb *self);static int ali_ircc_net_open(struct net_device *dev);static int ali_ircc_net_close(struct net_device *dev);static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud);static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev);/* SIR function */static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev);static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self);static void ali_ircc_sir_receive(struct ali_ircc_cb *self);static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self);static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len);static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed);/* FIR function */static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev);static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed);static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self);static int ali_ircc_dma_receive(struct ali_ircc_cb *self); static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self);static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self);static void ali_ircc_dma_xmit(struct ali_ircc_cb *self);/* My Function */static int ali_ircc_read_dongle_id (int i, chipio_t *info);static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed);/* ALi chip function */static void SIR2FIR(int iobase);static void FIR2SIR(int iobase);static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable);/* * Function ali_ircc_init () * * Initialize chip. Find out whay kinds of chips we are dealing with * and their configuation registers address */static int __init ali_ircc_init(void){ ali_chip_t *chip; chipio_t info; int ret; int cfg, cfg_base; int reg, revision; int i = 0; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); ret = platform_driver_register(&ali_ircc_driver); if (ret) { IRDA_ERROR("%s, Can't register driver!\n", ALI_IRCC_DRIVER_NAME); return ret; } ret = -ENODEV; /* Probe for all the ALi chipsets we know about */ for (chip= chips; chip->name; chip++, i++) { IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name); /* Try all config registers for this chip */ for (cfg=0; cfg<2; cfg++) { cfg_base = chip->cfg[cfg]; if (!cfg_base) continue; memset(&info, 0, sizeof(chipio_t)); info.cfg_base = cfg_base; info.fir_base = io[i]; info.dma = dma[i]; info.irq = irq[i]; /* Enter Configuration */ outb(chip->entr1, cfg_base); outb(chip->entr2, cfg_base); /* Select Logical Device 5 Registers (UART2) */ outb(0x07, cfg_base); outb(0x05, cfg_base+1); /* Read Chip Identification Register */ outb(chip->cid_index, cfg_base); reg = inb(cfg_base+1); if (reg == chip->cid_value) { IRDA_DEBUG(2, "%s(), Chip found at 0x%03x\n", __FUNCTION__, cfg_base); outb(0x1F, cfg_base); revision = inb(cfg_base+1); IRDA_DEBUG(2, "%s(), Found %s chip, revision=%d\n", __FUNCTION__, chip->name, revision); /* * If the user supplies the base address, then * we init the chip, if not we probe the values * set by the BIOS */ if (io[i] < 2000) { chip->init(chip, &info); } else { chip->probe(chip, &info); } if (ali_ircc_open(i, &info) == 0) ret = 0; i++; } else { IRDA_DEBUG(2, "%s(), No %s chip at 0x%03x\n", __FUNCTION__, chip->name, cfg_base); } /* Exit configuration */ outb(0xbb, cfg_base); } } IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); if (ret) platform_driver_unregister(&ali_ircc_driver); return ret;}/* * Function ali_ircc_cleanup () * * Close all configured chips * */static void __exit ali_ircc_cleanup(void){ int i; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); for (i=0; i < ARRAY_SIZE(dev_self); i++) { if (dev_self[i]) ali_ircc_close(dev_self[i]); } platform_driver_unregister(&ali_ircc_driver); IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);}/* * Function ali_ircc_open (int i, chipio_t *inf) * * Open driver instance * */static int ali_ircc_open(int i, chipio_t *info){ struct net_device *dev; struct ali_ircc_cb *self; int dongle_id; int err; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); if (i >= ARRAY_SIZE(dev_self)) { IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__); return -ENOMEM; } /* Set FIR FIFO and DMA Threshold */ if ((ali_ircc_setup(info)) == -1) return -1; dev = alloc_irdadev(sizeof(*self)); if (dev == NULL) { IRDA_ERROR("%s(), can't allocate memory for control block!\n", __FUNCTION__); return -ENOMEM; } self = dev->priv; self->netdev = dev; spin_lock_init(&self->lock); /* Need to store self somewhere */ dev_self[i] = self; self->index = i; /* Initialize IO */ self->io.cfg_base = info->cfg_base; /* In ali_ircc_probe_53 assign */ self->io.fir_base = info->fir_base; /* info->sir_base = info->fir_base */ self->io.sir_base = info->sir_base; /* ALi SIR and FIR use the same address */ self->io.irq = info->irq; self->io.fir_ext = CHIP_IO_EXTENT; self->io.dma = info->dma; self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */ /* Reserve the ioports that we need */ if (!request_region(self->io.fir_base, self->io.fir_ext, ALI_IRCC_DRIVER_NAME)) { IRDA_WARNING("%s(), can't get iobase of 0x%03x\n", __FUNCTION__, self->io.fir_base); err = -ENODEV; goto err_out1; } /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); /* The only value we must override it the baudrate */ self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); // benjamin 2000/11/8 05:27PM 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 = 14384; /* 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_out2; } 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_out3; } 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; /* Reset Tx queue info */ self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; self->tx_fifo.tail = self->tx_buff.head; /* Keep track of module usage */ SET_MODULE_OWNER(dev); /* Override the network functions we need to use */ dev->hard_start_xmit = ali_ircc_sir_hard_xmit; dev->open = ali_ircc_net_open; dev->stop = ali_ircc_net_close; dev->do_ioctl = ali_ircc_net_ioctl; dev->get_stats = ali_ircc_net_get_stats; err = register_netdev(dev); if (err) { IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); goto err_out4; } IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name); /* Check dongle id */ dongle_id = ali_ircc_read_dongle_id(i, info); IRDA_MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__, ALI_IRCC_DRIVER_NAME, dongle_types[dongle_id]); self->io.dongle_id = dongle_id; IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); return 0; err_out4: dma_free_coherent(NULL, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); err_out3: dma_free_coherent(NULL, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); err_out2: release_region(self->io.fir_base, self->io.fir_ext); err_out1: dev_self[i] = NULL; free_netdev(dev); return err;}/* * Function ali_ircc_close (self) * * Close driver instance * */static int __exit ali_ircc_close(struct ali_ircc_cb *self){ int iobase; IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return -1;); iobase = self->io.fir_base; /* Remove netdevice */ unregister_netdev(self->netdev); /* Release the PORT that this driver is using */ IRDA_DEBUG(4, "%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); dev_self[self->index] = NULL; free_netdev(self->netdev); IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); return 0;}/* * Function ali_ircc_init_43 (chip, info) * * Initialize the ALi M1543 chip. */static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info) { /* All controller information like I/O address, DMA channel, IRQ * are set by BIOS */ return 0;}/* * Function ali_ircc_init_53 (chip, info) * * Initialize the ALi M1535 chip. */static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info) { /* All controller information like I/O address, DMA channel, IRQ * are set by BIOS */ return 0;}/* * Function ali_ircc_probe_53 (chip, info) * * Probes for the ALi M1535D or M1535 */static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info){ int cfg_base = info->cfg_base; int hi, low, reg; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); /* Enter Configuration */ outb(chip->entr1, cfg_base); outb(chip->entr2, cfg_base); /* Select Logical Device 5 Registers (UART2) */ outb(0x07, cfg_base); outb(0x05, cfg_base+1); /* Read address control register */ outb(0x60, cfg_base); hi = inb(cfg_base+1); outb(0x61, cfg_base); low = inb(cfg_base+1); info->fir_base = (hi<<8) + low; info->sir_base = info->fir_base; IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, info->fir_base); /* Read IRQ control register */ outb(0x70, cfg_base); reg = inb(cfg_base+1); info->irq = reg & 0x0f; IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq); /* Read DMA channel */ outb(0x74, cfg_base); reg = inb(cfg_base+1); info->dma = reg & 0x07; if(info->dma == 0x04) IRDA_WARNING("%s(), No DMA channel assigned !\n", __FUNCTION__); else IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma); /* Read Enabled Status */ outb(0x30, cfg_base); reg = inb(cfg_base+1); info->enabled = (reg & 0x80) && (reg & 0x01); IRDA_DEBUG(2, "%s(), probing enabled=%d\n", __FUNCTION__, info->enabled); /* Read Power Status */ outb(0x22, cfg_base); reg = inb(cfg_base+1); info->suspended = (reg & 0x20); IRDA_DEBUG(2, "%s(), probing suspended=%d\n", __FUNCTION__, info->suspended); /* Exit configuration */ outb(0xbb, cfg_base); IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); return 0; }/* * Function ali_ircc_setup (info) * * Set FIR FIFO and DMA Threshold * Returns non-negative on success. * */static int ali_ircc_setup(chipio_t *info){ unsigned char tmp; int version; int iobase = info->fir_base; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); /* Locking comments : * Most operations here need to be protected. We are called before * the device instance is created in ali_ircc_open(), therefore * nobody can bother us - Jean II */ /* Switch to FIR space */ SIR2FIR(iobase); /* Master Reset */ outb(0x40, iobase+FIR_MCR); // benjamin 2000/11/30 11:45AM /* Read FIR ID Version Register */ switch_bank(iobase, BANK3); version = inb(iobase+FIR_ID_VR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -