patch-2.4.7 linux/drivers/ieee1394/aic5800.c
Next file: linux/drivers/ieee1394/aic5800.h
Previous file: linux/drivers/ieee1394/Makefile
Back to the patch index
Back to the overall index
- Lines: 903
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.4.6/linux/drivers/ieee1394/aic5800.c
- Orig date:
Fri Mar 2 18:38:38 2001
diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/aic5800.c linux/drivers/ieee1394/aic5800.c
@@ -1,902 +0,0 @@
-/*
- * +++ THIS DRIVER IS ORPHANED AND UNSUPPORTED +++
- *
- * aic5800.c - Adaptec AIC-5800 PCI-IEEE1394 chip driver
- * Copyright (C)1999 Emanuel Pirker <epirker@edu.uni-klu.ac.at>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/delay.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "ieee1394.h"
-#include "aic5800.h"
-
-
-
-/// print general (card independent) information
-#define PRINT_G(level, fmt, args...) printk(level "aic5800: " fmt "\n" , ## args)
-/// print card specific information
-#define PRINT(level, card, fmt, args...) printk(level "aic5800-%d: " fmt "\n" , card , ## args)
-
-/// card array
-static struct aic5800 cards[MAX_AIC5800_CARDS];
-/// holds the number of installed aic5800 cards
-static int num_of_cards = 0;
-
-static int add_card(struct pci_dev *dev);
-static void remove_card(struct aic5800 *aic);
-static int init_driver(void);
-
-
-/*****************************************************************
- * Auxiliary functions needed to read the EEPROM
- * Daniel Minitti
- *****************************************************************/
-#define SEEPDOUT 0x1
-#define SEEPDIN 0x02
-#define SEEPSK 0x04
-#define SEEPCS 0x08
-#define SEEPCYC 0x10
-#define SEEPBUSY 0x20
-
-#define CLOCK_PULSE() {\
- int cnt=200;\
- while(cnt-->0 && reg_read(aic, misc_SEEPCTL) & SEEPBUSY);\
- if (reg_read(aic, misc_SEEPCTL) & SEEPBUSY) printk("BUSY ");\
- }
-
-static inline unsigned short read_seeprom_word(struct aic5800 *aic,
- int offset)
-{
- int i;
- unsigned char temp;
- unsigned char read_cmd[3] = {1,1,0};
- unsigned short rd;
-
- // send chip select for one clock cycle.
- reg_write(aic, misc_SEEPCTL, SEEPSK|SEEPCS);
- CLOCK_PULSE();
-
- // write start bit (1) & READ op-code (10b)
- for (i=0; i<sizeof(read_cmd); i++) {
- temp = SEEPCS | SEEPCYC | read_cmd[i];
- reg_write(aic, misc_SEEPCTL, temp);
- CLOCK_PULSE();
- temp = temp ^ SEEPSK;
- reg_write(aic, misc_SEEPCTL, temp);
- CLOCK_PULSE();
- }
- // write 8 bit address (MSB --> LSB)
- for (i=7; i>=0; i--) {
- temp = offset;
- temp = (temp >> i) & 1;
- temp = SEEPCS | SEEPCYC | temp;
- reg_write(aic, misc_SEEPCTL, temp);
- CLOCK_PULSE();
- temp = temp ^ SEEPSK;
- reg_write(aic, misc_SEEPCTL, temp);
- CLOCK_PULSE();
- }
- // read 16 bit (MSB --> LSB)
- rd = 0;
- for (i=0; i<=16; i++) {
- temp = SEEPCS | SEEPCYC;
- reg_write(aic, misc_SEEPCTL, temp);
- CLOCK_PULSE();
- temp = temp ^ SEEPSK;
- rd = (rd << 1) | (unsigned short)((reg_read(aic, misc_SEEPCTL)
-& SEEPDIN)>>1);
- reg_write(aic, misc_SEEPCTL, temp);
- CLOCK_PULSE();
- }
-
- // reset chip select for the next command cycle
- reg_write(aic, misc_SEEPCTL, SEEPCYC);
- CLOCK_PULSE();
- reg_write(aic, misc_SEEPCTL, SEEPCYC | SEEPSK);
- CLOCK_PULSE();
- reg_write(aic, misc_SEEPCTL, SEEPCYC);
- CLOCK_PULSE();
-
- reg_write(aic, misc_SEEPCTL, 0);
- CLOCK_PULSE();
-
- return rd;
-}
-
-#undef DEBUG_SEEPROM
-
-/** Read 64-bit GUID (Global Unique ID) from SEEPROM
- *
- * It works well on AHA-8945.
- * On AHA-8920 it works well only on first time, It returns ffff... on
- * the other times.
- *****************************************************************/
-static unsigned long long read_guid(struct aic5800 *aic)
-{
- int i;
- unsigned long long guid;
-
-#ifdef DEBUG_SEEPROM
- printk("\n");
- printk("SEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL));
-#endif
-
- /* read GUID */
- guid = 0;
- for (i=0x10; i<0x14; i++)
- guid = (guid << 16) | read_seeprom_word(aic,i);
-
-#ifdef DEBUG_SEEPROM
- for (i=0; i<3; i++)
- printk("%x ", (unsigned int) read_seeprom_word(aic,i));
- printk("\nGUID = ");
- for (i=3; i>=0; i--)
- printk("%x ", (unsigned int)(guid>>(16*i))&0xffff);
-
- printk("\nSEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL));
-#endif
- return guid;
-}
-
-#undef CLOCK_PULSE()
-
-static int aic_detect(struct hpsb_host_template *tmpl)
-{
- struct hpsb_host *host;
- int i;
-
- init_driver();
-
- for (i = 0; i < num_of_cards; i++) {
- host = hpsb_get_host(tmpl, 0);
- if (host == NULL) {
- /* simply don't init more after out of mem */
- return i;
- }
- host->hostdata = &cards[i];
- cards[i].host = host;
- }
-
- return num_of_cards;
-}
-
-static int aic_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
- struct aic5800 *aic = host->hostdata;
- int retval = 0;
- unsigned long flags;
- struct hpsb_packet *packet, *lastpacket;
-
- switch (cmd) {
- case RESET_BUS:
- reg_write(aic, misc_PhyControl, 0x00004140 );
- break;
-
- case GET_CYCLE_COUNTER:
- arg = reg_read(aic, misc_CycleTimer);
- break;
-
- case SET_CYCLE_COUNTER:
- reg_write(aic, misc_CycleTimer, arg);
- break;
-
- case SET_BUS_ID:
- reg_clear_bits(aic, misc_NodeID, 0xFFC0);
- reg_set_bits(aic, misc_NodeID, (arg<<6));
- break;
-
- case ACT_CYCLE_MASTER:
- if (arg) {
- /* enable cycleMaster */
- reg_set_bits(aic, misc_Control, 0x20000);
- } else {
- /* disable cycleMaster */
- reg_clear_bits(aic, misc_Control, 0x20000);
- };
- break;
-
- case CANCEL_REQUESTS:
- spin_lock_irqsave(&aic->async_queue_lock, flags);
- /* stop any chip activity */
- reg_write( aic, AT_ChannelControl, 0x80000000);
- packet = aic->async_queue;
- aic->async_queue = NULL;
- spin_unlock_irqrestore(&aic->async_queue_lock, flags);
-
- while (packet != NULL) {
- lastpacket = packet;
- packet = packet->xnext;
- hpsb_packet_sent(host, lastpacket, ACKX_ABORTED);
- }
-
- break;
-
- case MODIFY_USAGE:
- if (arg) {
- MOD_INC_USE_COUNT;
- } else {
- MOD_DEC_USE_COUNT;
- }
- break;
-
-#if 0
- case DEBUG_DUMPINFO:
- PRINT(KERN_INFO, aic->id, AIC5800_DRIVER_NAME);
- PRINT(KERN_INFO, aic->id, " Register MMIO base: 0x%p\n",
- aic->registers);
- PRINT(KERN_INFO, aic->id, " NodeID: 0x%x\n",
- reg_read(aic, misc_NodeID) );
- PRINT(KERN_INFO,aic->id, " #Intr: %lu BusResets: %lu\n",
- aic->NumInterrupts, aic->NumBusResets);
- PRINT(KERN_INFO, aic->id, " TxPackets: %lu RxPackets: %lu\n",
- aic->TxPackets, aic->RxPackets);
- PRINT(KERN_INFO,aic->id, " TxRdy: %lu ATErr: %lu HdrErr: %lu TcodeErr: %lu SendRej: %lu\n",
- aic->TxRdy, aic->ATError, aic->HdrErr,
- aic->TCodeErr, aic->SendRej);
- break;
-#endif
-
- default:
- PRINT(KERN_ERR, aic->id, "unknown devctl command %d", cmd);
- retval = -1;
- }
-
- return retval;
-
-}
-
-/** Initialize the host adapter chip and corresponding data
- structures. We reset the chip, enable transmitter, receiver,
- the physical DMA units, cycle timer, cycle source, reception
- of selfid packets and initialize several other registers. */
-static int aic_initialize(struct hpsb_host *host)
-{
- int i;
- struct aic5800 *aic = host->hostdata;
-
- /* Reset data structures */
- aic->async_queue = NULL;
- spin_lock_init(&aic->async_queue_lock);
-
- /* Reset the chip */
- reg_write( aic, misc_Reset, 0x37);
- udelay(10); // FIXME
- reg_write( aic, misc_Reset, 0);
-
- /* Enable Transmitter/Receiver, enable physDMA,
- * enable CycleTimer, cycleSource */
- reg_write( aic, misc_Control, 0x82050003);
-
- /* Enable reception of SelfID packets */
- reg_set_bits(aic, misc_PacketControl, 0x20);
-
- reg_write(aic, AT_InterruptSelect, 0x00F0001);
- reg_write(aic, AT_BranchSelect, 0x0100010);
- reg_write(aic, AT_WaitSelect, 0x00F0001);
- reg_write(aic, misc_ATRetries, reg_read(aic, misc_ATRetries) | 0x7);
-
- /* initialize AR DMA */
-
- /* unset run bit */
- reg_write( aic, AR_ChannelControl, 0x80000000);
-
- /* here we should have 0 iterations because of the code
- in the DmaAR handler. However, to be sure we do it */
- i = 0;
- while (reg_read(aic, AR_ChannelStatus) & 0x400) {
- i++;
- if (i>100000) {
- PRINT(KERN_ERR, aic->id,
- "Huh! Can't set AR_ChannelControl... card can not receive!");
- break;
- }
- }
-
- (aic->AR_program)->control = ( DMA_CMD_INPUTLAST | DMA_KEY_STREAM0
- | DMA_INTR_ALWAYS | DMA_BRANCH_ALWAYS)
- + AIC5800_ARFIFO_SIZE;
- (aic->AR_program)->address = virt_to_bus(aic->rcv_page);
- (aic->AR_program)->branchAddress = virt_to_bus(aic->AR_program);
- (aic->AR_program)->status = AIC5800_ARFIFO_SIZE;
-
- (aic->AR_program+1)->control = DMA_CMD_STOP;
- (aic->AR_program+1)->address = 0;
- (aic->AR_program+1)->branchAddress = 0;
- (aic->AR_program+1)->status = 0;
-
- reg_write( aic, AR_CommandPtr, (u32) virt_to_bus(aic->AR_program));
- reg_write( aic, AR_ChannelControl, 0x80008000);
-
- /* Enable Interrupts */
- reg_write(aic, misc_InterruptClear, 0xFFFFFFFF);
- reg_write(aic, misc_InterruptMask, 0xFFFFFFFF);
- /*reg_write(aic, misc_InterruptMask, 0x00F1F03F);*/
-
- return 1;
-}
-
-static void aic_release(struct hpsb_host *host)
-{
- struct aic5800 *aic;
-
- if (host != NULL) {
- aic = host->hostdata;
- remove_card(aic);
- }
-}
-
-/* This must be called with the async_queue_lock held. */
-static void send_next_async(struct aic5800 *aic)
-{
- int i;
- struct hpsb_packet *packet = aic->async_queue;
-
- /* stop the channel program if it's still running */
- reg_write( aic, AT_ChannelControl, 0x80000000);
-
- /* re-format packet header for AIC-5800 chip */
- packet->header[1] = (packet->header[1] & 0xFFFF) |
- (packet->header[0] & 0xFFFF0000);
- packet->header[0] = (packet->header[0] & 0xFFFF);
-
-#ifndef __BIG_ENDIAN
- /* Packet must be byte-swapped in non-big-endian environments,
- * see AIC-5800 specification...
- */
- { u32 i;
- for ( i = 0 ; i < packet->header_size/sizeof(u32) ; i++ )
- packet->header[i] = cpu_to_be32( packet->header[i] );
- for ( i = 0 ; i < packet->data_size/sizeof(u32) ; i++ )
- packet->data[i] = cpu_to_be32( packet->data[i] );
- }
-
-#endif
-
- /* typically we use only a few iterations here */
- i = 0;
- while (reg_read(aic, AT_ChannelStatus) & 0x400) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR, aic->id,
- "runaway loop 1 in send_next_async() - bailing out...");
- break;
- };
- };
-
- /* set data buffer address and packet length */
- memset(aic->AT_program, 0, MAX_AT_PROGRAM_SIZE * sizeof(struct dma_cmd));
-
- if (packet->data_size) {
- aic->AT_program[0].control = ( DMA_CMD_OUTPUTMORE | DMA_KEY_STREAM0 ) +
- packet -> header_size;
- aic->AT_program[0].address = virt_to_bus( packet->header );
- aic->AT_program[1].control = ( DMA_CMD_OUTPUTLAST | DMA_KEY_STREAM0
- | DMA_INTR_ALWAYS )
- + packet -> data_size;
- aic->AT_program[1].address = virt_to_bus( packet->data );
-
- aic->AT_program[2].control = DMA_CMD_STOP;
-
- } else {
- aic->AT_program[0].control = ( DMA_CMD_OUTPUTLAST | DMA_INTR_ALWAYS |
- DMA_KEY_STREAM0 ) +
- packet -> header_size;
- aic->AT_program[0].address = virt_to_bus( packet->header );
-
- aic->AT_program[1].control = DMA_CMD_STOP;
- };
-
- /* set program start address */
- reg_write(aic, AT_CommandPtr, (unsigned int) virt_to_bus(aic->AT_program));
-
- /* typically we use only a few iterations here */
- i = 0;
- while (reg_read(aic, AT_CommandPtr) != (unsigned int)
- virt_to_bus(aic->AT_program)) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR, aic->id,
- "runaway loop 2 in send_next_async() - bailing out...");
- break;
- };
- };
-
- /* run program */
- reg_write( aic, AT_ChannelControl, 0x80008000);
-}
-
-
-static int aic_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
- struct aic5800 *aic = host->hostdata;
- struct hpsb_packet *p;
- unsigned long flags;
-
- if (packet->data_size >= 4096) {
- PRINT(KERN_ERR, aic->id, "transmit packet data too big (%d)",
- packet->data_size);
- return 0;
- }
-
- packet->xnext = NULL;
-
- spin_lock_irqsave(&aic->async_queue_lock, flags);
-
- if (aic->async_queue == NULL) {
- aic->async_queue = packet;
- send_next_async(aic);
- } else {
- p = aic->async_queue;
- while (p->xnext != NULL) {
- p = p->xnext;
- }
-
- p->xnext = packet;
- }
-
- spin_unlock_irqrestore(&aic->async_queue_lock, flags);
-
- return 1;
-}
-
-static int get_phy_reg(struct aic5800 *aic, int addr)
-{
- int retval;
- int i = 0;
-
- /* sanity check */
- if (addr > 15) {
- PRINT(KERN_ERR, aic->id, __FUNCTION__
- ": PHY register address %d out of range", addr);
- return -1;
- }
-
- /* request data from PHY */
- reg_write(aic, misc_PhyControl, LINK_PHY_READ | LINK_PHY_ADDR(addr));
-
- /* read data from PhyControl register */
- /* note that we have to wait until the register is updated */
- do {
- retval = reg_read(aic, misc_PhyControl);
-
- if (i > 10000) {
- PRINT(KERN_ERR, aic->id, __FUNCTION__
- ": runaway loop, aborting");
- retval = -1;
- break;
- }
- i++;
- } while ((retval & 0xf000000) != LINK_PHY_RADDR(addr));
-
- /* we don't want a PhyInt interrupt */
- reg_write(aic, misc_InterruptClear, INT_PhyInt);
-
- if (retval != -1) {
- return ((retval & 0xff0000)>>16);
- } else {
- return -1;
- }
-}
-
-static quadlet_t generate_own_selfid(struct aic5800 *aic, int phyid)
-{
- quadlet_t lsid;
- char phyreg[7];
- int i;
-
- for (i = 1; i < 7; i++) {
- phyreg[i] = get_phy_reg(aic, i);
- }
-
- /* Standard PHY register map */
- lsid = 0x80400000 | (phyid << 24);
- lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */
- lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */
- lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dep) */
- lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */
-
- for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */
- if (phyreg[3 + i] & 0x4) {
- lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)
- << (6 - i*2);
- } else {
- lsid |= 1 << (6 - i*2);
- }
- }
-
- return lsid;
-};
-
-/* moved out to make interrupt routine more readable */
-inline static void handle_selfid(struct aic5800 *aic, struct hpsb_host *host,
- int phyid, int isroot, size_t size)
-{
- quadlet_t *q = aic->rcv_page;
- quadlet_t lsid;
-
- /* we need our own self-id packet */
- lsid = generate_own_selfid(aic, phyid);
-
- /* unconnected state? only begin and end marker in rcv_page */
- if (size==8) {
- hpsb_selfid_received(host, lsid);
- }
-
- /* process buffer... AIC's FIFO often contains some strangenesses */
- while (size > 0) {
- if (q[0] == 0xe0) {
- /* marker */
- q += 1;
- size -= 4;
- continue;
- };
- if (q[0] == 0x1) {
- /* marker */
- q += 1;
- size -= 4;
- break;
- };
-
- if (q[0] == ~q[1]) {
- /* correct self-id */
-
- if ((q[0] & 0x3f800000) == ((phyid + 1) << 24)) {
- /* its our turn now! */
- //PRINT(KERN_INFO,
- // aic->id, "selfid packet 0x%x included", lsid);
-
- hpsb_selfid_received(host, lsid);
- }
-
- //PRINT(KERN_INFO, aic->id, "selfid packet 0x%x rcvd", q[0]);
- hpsb_selfid_received(host, q[0]);
- q += 2;
- size -= 8;
- continue;
- };
- }
-
- /* if we are root, our self-id packet is last */
- if (isroot && phyid != 0) {
- hpsb_selfid_received(host, lsid);
- }
-
- hpsb_selfid_complete(host, phyid, isroot);
-}
-
-static void aic_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct aic5800 *aic = (struct aic5800 *)dev_id;
- struct hpsb_host *host = aic->host;
- quadlet_t *q = aic->rcv_page;
-
- int phyid = -1, isroot = 0;
-
- u32 interruptEvent = reg_read(aic, misc_InterruptEvents);
- reg_write(aic, misc_InterruptClear, interruptEvent);
-
- //printk("InterruptEvent 0x%x\n", interruptEvent);
- if ( (interruptEvent & 0x3f) == 0x3f ) {
- PRINT(KERN_INFO, aic->id, "Dma Engine Error");
- };
-
- if ( interruptEvent & INT_DmaAT ) {
- if (aic->AT_program[0].status & 0xFFFF)
- PRINT(KERN_INFO, aic->id, "AT: could not transfer %d bytes",
- aic->AT_program[0].status & 0xFFFF);
- };
-
- if ( interruptEvent & INT_PhyInt) {
- PRINT(KERN_INFO, aic->id, "PhyInt");
- };
-
- if ( interruptEvent & INT_DmaAR ) {
- int rcv_bytes;
- int i;
-
- /* we calculate the number of received bytes from the
- residual count field */
- rcv_bytes = AIC5800_ARFIFO_SIZE - (aic->AR_program->status & 0xFFFF);
-
- //PRINT(KERN_INFO, aic->id, "AR_status 0x%x, %d bytes read", aic->AR_program->status, rcv_bytes);
-
- if ((aic->AR_program->status & 0x84000000)
- && (aic->AR_program->status & 0xFFFF) >= 8 ) {
-
-#ifndef __BIG_ENDIAN
- /* we have to do byte-swapping on non-bigendian architectures */
- for (i=0; i< (rcv_bytes / sizeof(quadlet_t)); i++) {
- *q = be32_to_cpu(*q);
- q++;
- };
- q = aic->rcv_page;
-#endif
-
- if (*q == 0xe0) {
- phyid = reg_read(aic, misc_NodeID);
- isroot = phyid & 0x800000;
- phyid = phyid & 0x3F;
- handle_selfid(aic, host, phyid, isroot, rcv_bytes);
- } else {
- hpsb_packet_received(host, aic->rcv_page, rcv_bytes, 0);
- };
- } else {
- PRINT(KERN_ERR, aic->id,
- "AR DMA program status value 0x%x is incorrect!",
- aic->AR_program->status);
- };
- }
- if ( interruptEvent & INT_BusReset ) {
- PRINT(KERN_INFO, aic->id, "bus reset occurred");
- if (!host->in_bus_reset) {
- hpsb_bus_reset(host);
- }
- reg_set_bits(aic, misc_Control, 0x1);
- aic->NumBusResets++;
- };
-
- if (interruptEvent & INT_RcvData ) {
- aic->RxPackets++;
- };
-
- if (interruptEvent & INT_TxRdy) {
- /* async packet sent - transmitter ready */
- u32 ack;
- struct hpsb_packet *packet;
-
- if (aic->async_queue) {
-
- spin_lock(&aic->async_queue_lock);
-
-
- ack = reg_read(aic, AT_ChannelStatus) & 0xF;
-
- packet = aic->async_queue;
- aic->async_queue = packet->xnext;
-
- if (aic->async_queue != NULL) {
- send_next_async(aic);
- }
- spin_unlock(&aic->async_queue_lock);
- PRINT(KERN_INFO,aic->id,"packet sent with ack code %d",ack);
- hpsb_packet_sent(host, packet, ack);
- } // else
- //PRINT(KERN_INFO,aic->id,"packet sent without async_queue (self-id?)");
-
- aic->TxRdy++;
- };
- if (interruptEvent & INT_ATError ) {
- PRINT(KERN_INFO,aic->id,"ATError");
- aic->ATError++;
- };
- if (interruptEvent & INT_SendRej ) {
- aic->SendRej++;
- };
- if (interruptEvent & INT_HdrErr ) {
- aic->HdrErr++;
- };
- if (interruptEvent & INT_TCodeErr ) {
- PRINT(KERN_INFO,aic->id,"TCodeErr");
- aic->TCodeErr++;
- };
-
- aic->NumInterrupts++;
-
-}
-
-inline static void * quadquadalign(void *buf)
-{
- if ((unsigned int) buf % 0x10 != 0) {
- return (void *)(((unsigned int)buf + 0x10) & 0xFFFFFFF0);
- } else {
- return buf;
- };
-}
-
-static int add_card(struct pci_dev *dev)
-{
-#define FAIL(fmt, args...) do {\
- PRINT_G(KERN_ERR, fmt , ## args); \
- num_of_cards--; \
- remove_card(aic); \
- return 1; } while (0)
-
- struct aic5800 *aic; /* shortcut to currently handled device */
- unsigned long page;
-
- if (pci_enable_device(dev))
- return 1;
-
- if (num_of_cards == MAX_AIC5800_CARDS) {
- PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
- "Adjust MAX_AIC5800_CARDS in aic5800.h.",
- MAX_AIC5800_CARDS);
- return 1;
- }
-
- aic = &cards[num_of_cards++];
-
- aic->id = num_of_cards-1;
- aic->dev = dev;
-
- if (!request_irq(dev->irq, aic_irq_handler, SA_SHIRQ,
- AIC5800_DRIVER_NAME, aic)) {
- PRINT(KERN_INFO, aic->id, "allocated interrupt %d", dev->irq);
- } else {
- FAIL("failed to allocate shared interrupt %d", dev->irq);
- }
-
- page = get_free_page(GFP_KERNEL);
- if (page != 0) {
- aic->rcv_page = phys_to_virt(page);
- } else {
- FAIL("failed to allocate receive buffer");
- }
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
- aic->registers = ioremap_nocache(dev->base_address[0],
- AIC5800_REGSPACE_SIZE);
-#else
- aic->registers = ioremap_nocache(dev->resource[0].start,
- AIC5800_REGSPACE_SIZE);
-#endif
-
- if (aic->registers == NULL) {
- FAIL("failed to remap registers - card not accessible");
- }
-
- PRINT(KERN_INFO, aic->id, "remapped memory space reg 0x%p",
- aic->registers);
-
- aic->pbuf = kmalloc(AIC5800_PBUF_SIZE, GFP_KERNEL);
-
- if (!aic->pbuf) {
- FAIL("failed to allocate program buffer");
- }
-
- aic->AT_program = quadquadalign(aic->pbuf);
- aic->AT_program[2].control = DMA_CMD_STOP;
-
- aic->AR_program = aic->AT_program + MAX_AT_PROGRAM_SIZE *
- sizeof(struct dma_cmd);
-
- return 0;
-#undef FAIL
-}
-
-static void remove_card(struct aic5800 *aic)
-{
- /* Disable interrupts of this controller */
- reg_write(aic, misc_InterruptMask, 0);
- /* Free AR buffer */
- free_page(virt_to_phys(aic->rcv_page));
- /* Free channel program buffer */
- kfree(aic->pbuf);
- /* Free interrupt request */
- free_irq(aic->dev->irq, aic);
- /* Unmap register space */
- iounmap(aic->registers);
-}
-
-static int init_driver()
-{
- struct pci_dev *dev = NULL;
- int success = 0;
-
- if (num_of_cards) {
- PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
- return 0;
- }
-
- while ((dev = pci_find_device(PCI_VENDOR_ID_ADAPTEC,
- PCI_DEVICE_ID_ADAPTEC_5800, dev))
- != NULL) {
- if (add_card(dev) == 0) {
- success = 1;
- }
- }
-
- if (success == 0) {
- PRINT_G(KERN_WARNING, "no operable AIC-5800 based cards found");
- return -ENXIO;
- }
-
- return 0;
-}
-
-/** Prepare our local CSR ROM. This is done by using the software-stored
- ROM and inserting the GUID read from the EEPROM */
-static size_t get_aic_rom(struct hpsb_host *host, const quadlet_t **ptr)
-{
- struct aic5800 *aic = host -> hostdata;
- u64 guid;
-
- /* Read the GUID from the card's EEPROM and put it into the right
- place in the CONFIG ROM. */
- guid = read_guid(aic);
- aic5800_csr_rom[15] = (u32) (guid >> 32);
- aic5800_csr_rom[16] = (u32) (guid & 0xFFFF);
-
- *ptr = aic5800_csr_rom;
-
- return sizeof(aic5800_csr_rom);
-}
-
-struct hpsb_host_template *get_aic_template(void)
-{
- static struct hpsb_host_template tmpl;
- static int initialized = 0;
-
- if (!initialized) {
- /* Initialize by field names so that a template structure
- * reorganization does not influence this code. */
- tmpl.name = "aic5800";
-
- tmpl.detect_hosts = aic_detect;
- tmpl.initialize_host = aic_initialize;
- tmpl.release_host = aic_release;
- tmpl.get_rom = get_aic_rom;
- tmpl.transmit_packet = aic_transmit;
- tmpl.devctl = aic_devctl;
-
- initialized = 1;
- }
-
- return &tmpl;
-}
-
-#ifdef MODULE
-
-/* EXPORT_NO_SYMBOLS; */
-
-MODULE_AUTHOR("Emanuel Pirker <epirker@edu.uni-klu.ac.at>");
-MODULE_DESCRIPTION("Adaptec AIC-5800 PCI-to-IEEE1394 controller driver");
-MODULE_SUPPORTED_DEVICE("aic5800");
-
-void cleanup_module(void)
-{
- hpsb_unregister_lowlevel(get_aic_template());
- PRINT_G(KERN_INFO, "removed " AIC5800_DRIVER_NAME " module");
-}
-
-int init_module(void)
-{
- if (hpsb_register_lowlevel(get_aic_template())) {
- PRINT_G(KERN_ERR, "registering failed");
- return -ENXIO;
- } else {
- return 0;
- }
-}
-
-#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)