Hi all,

I have changed the Major of my drivers at 251 and 252 and now all work fine.

Thanks.

-----Mensaje original-----
De: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
En nombre de rflores
Enviado el: lunes, 09 de julio de 2007 15:23
Para: 'uClinux development list'
Asunto: [uClinux-dev] open device problem

Hi All,

I'm writing two character drivers under uClinux in a AT91, one is a simple
driver that, through ioctl, writes and reads in specific HW registers; the
other is a software emulated spi which uses a timer and interrupts.

If I compile the kernel with only one of this drivers, all the operations
over the device driver (open, read, write, close, ioctl) work correctly, but
if I compile the kernel with two drivers, I can't open any device in the
application. It returns with errno=20 (Not a directory).

I create the devices under the Makefile of the vendor.

DEVICES =   \
\
spi,c,120,1 \
\
swg,c,50,1  \
\

In the uClinux start-up, the drivers executes all the init function
correctly


Zarlink MVTX2801A detected
Zarlink Port0 detected : Link up , Gigabit Ethernet Mode , Full Duplex  Mode
, Flow Control Enable
Zarlink Port1 detected : Link down , Gigabit Ethernet Mode , 
Zarlink Port2 detected : Link up , Gigabit Ethernet Mode , Full Duplex  Mode
, Flow Control Enable
Zarlink Port3 detected : Link up , Gigabit Ethernet Mode , Full Duplex  Mode
, Flow Control Enable

SWSPI: Initializating Software SPI driver for AT91xx40
SWSPI: Attached at Timer-2 (irq = 6)

But, in the application, the open function returns -1 and errno = 20.

/> 
/> llaccess test

Unable open device

errno = 20/> 
/>

If I only compile with one driver:

Zarlink MVTX2801A detected
Zarlink Port0 detected : Link up , Gigabit Ethernet Mode , Full Duplex  Mode
, Flow Control Enable
Zarlink Port1 detected : Link down , Gigabit Ethernet Mode , 
Zarlink Port2 detected : Link up , Gigabit Ethernet Mode , Full Duplex  Mode
, Flow Control Enable
Zarlink Port3 detected : Link up , Gigabit Ethernet Mode , Full Duplex  Mode
, Flow Control Enable

/> llaccess test

Open = 3

IOCTL 0x9d00 = 0xda

IOCTL 0x9d01 = 0x97

IOCTL 0x9d01 = 0x98

IOCTL 0x9d01 = 0x97

IOCTL 0x9d01 = 0x97
/>

What's wrong?

All source code of these drivers:

sd_api_conf.h
#ifndef _SD_API_CONF_H_
#define _SD_API_CONF_H_

  #define SD_PIN_NSS     25  
  #define SD_PIN_PROTECT 24
  #define SD_PIN_PRESENT 11
  #define SD_PIN_MISO    20
  #define SD_PIN_MOSI    19
  #define SD_PIN_SCK     18

  #define SD_IDLE_WAIT_MAX 1000000

  #define SD_BLOCKSIZE       512
  #define SD_BLOCKSIZE_NBITS 9

#endif




spi.h
#ifndef _SPI_H_
#define _SPI_H_

  #define SWSPI_MAJOR 120
  #define SWSPI_FREQ  20000
  #define SWSPI_RC  (CONFIG_ARM_CLK>>1)/SWSPI_FREQ
  /*Capture Mode Register*/
  #define TCCLKS(x)  (x & 0x07) << 0
  #define CLKI(x)    (x & 0x01) << 3
  #define BURST(x)   (x & 0x03) << 4
  #define LDBSTOP(x) (x & 0x01) << 5
  #define LDBDIS(x)  (x & 0x01) << 7
  #define ETRGEDG(x) (x & 0x03) << 8
  #define ABETRG(x)  (x & 0x01) << 10
  #define CPCTRG(x)  (x & 0x01) << 14
  #define WAVE(x)    (x & 0x01) << 15
  #define LDRA(x)    (x & 0x03) << 16
  #define LDRB(x)    (x & 0x03) << 18

 
  static int __init swspi_init (void);
  int spi_send_byte (char byte);
  char spi_receive_byte (void);
  static ssize_t swspi_write (struct file *filp,const char *buf,ssize_t
count,loff_t *f_pos);
  static ssize_t swspi_read (struct file *filp,char *buf, ssize_t
count,loff_t *f_pos);
  static int spi_open(struct inode *inode, struct file *filp);
  static int spi_release(struct inode *inode, struct file *filp);
  void spi_cs_assert (void);
  void spi_cs_deassert (void);
  static void SWSPI_IRQ_Handler (int irq,void *dev_id,struct pt_regs *regs);
  
#endif

spi.c
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/delay.h>

#include <linux/fs.h>
#include <linux/iobuf.h>
#include <linux/major.h>
#include <linux/blkdev.h>
#include <linux/raw.h>
#include <linux/interrupt.h>
#include <linux/capability.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>

#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/semaphore.h>

#include <asm/arch/widewlan.h>

#include "sd_api_conf.h"
#include "spi.h"

#if (SPI_TIMER==0)
#   define SPI_TIMER_IRQ_NUM IRQ_TC0
#elif (SPI_TIMER==1)
#   define SPI_TIMER_IRQ_NUM IRQ_TC1
#elif (SPI_TIMER==2)
#   define SPI_TIMER_IRQ_NUM IRQ_TC2
#else
#error Wierd -- SPI_TIMER is not defined or something....
#endif


static char spi_byte = 0;
static int openflag_spi = 0;
static spinlock_t irq_spi_lock;
static struct semaphore spi_sem;
 
static struct irqaction spi_timer_irq = 
  { SWSPI_IRQ_Handler, 0, 0, "swspi", NULL, NULL };

extern int setup_arm_irq(int, struct irqaction *);
extern void at91_mask_irq(unsigned int irq);
extern void at91_unmask_irq(unsigned int irq);
extern void at91_mask_ack_irq(unsigned int irq);


EXPORT_SYMBOL(swspi_init);
EXPORT_SYMBOL(swspi_cleanup);

static struct file_operations swspi_fops = {
          read:           swspi_read,
          write:          swspi_write,
          open:           spi_open,
          release:        spi_release,
  //        ioctl:          spi_ioctl,
};

static int spi_open(struct inode *inode, struct file *filp)
{
  if ( openflag_spi )
    return -EBUSY;

  MOD_INC_USE_COUNT;
  openflag_spi = 1;
  return 0;
}

static int spi_release(struct inode *inode, struct file *filp)
{
  openflag_spi = 0;
  MOD_DEC_USE_COUNT;
  return 0;
}

static int cleanup_swspi (void){
  return (unregister_chrdev(SWSPI_MAJOR, "spi"));
}

static int __init swspi_init (void)
{

   int result;

   if (SPI_TIMER == KERNEL_TIMER){
     printk(KERN_INFO "SWSPI: Timer is the same that Kernel Timer.... driver
not initializated\n");
     return (-1);
   }
   printk(KERN_INFO "SWSPI: Initializating Software SPI driver for
AT91xx40\n");
   result = register_chrdev(SWSPI_MAJOR, "spi", &swspi_fops);
   if( result < 0 ){
     printk(KERN_INFO "SWSPI: Unable to get %d major\n",SWSPI_MAJOR);
     return result;
   }

   /*SPI timer structures*/
   register volatile struct at91_timers* tt = (struct at91_timers*)
(AT91_TC_BASE);
   register volatile struct at91_timer_channel* tc =
&tt->chans[SPI_TIMER].ch;

   /* enable Spi timer */
   HW_AT91_TIMER_INIT(SPI_TIMER)
   
   /*Configuring SD/SPI I/O pins*/
   /*Enable SD/SPI pins as General Purpose IO Pins*/
   /*Those pines are for GCM-AT91 Board*/
   ((volatile struct pio_regs *)AT91_PIOA_BASE)->per =
PIO(SD_PIN_NSS)|PIO(SD_PIN_PROTECT)| PIO(SD_PIN_PRESENT)|
                                                         PIO(SD_PIN_MISO)|
PIO(SD_PIN_MOSI)| PIO(SD_PIN_SCK);
   /*Disable Interrupts for those pins*/
   ((volatile struct pio_regs *)AT91_PIOA_BASE)->idr =
PIO(SD_PIN_NSS)|PIO(SD_PIN_PROTECT)| PIO(SD_PIN_PRESENT)|
                                                        PIO(SD_PIN_MISO)|
PIO(SD_PIN_MOSI)| PIO(SD_PIN_SCK);
   /*Enable NSS, MOSI and SCK as outputs*/
   ((volatile struct pio_regs *)AT91_PIOA_BASE)->oer =  PIO(SD_PIN_NSS) |
PIO(SD_PIN_MOSI)| PIO(SD_PIN_SCK);
   /*Enable PROTECT, PRESENT and MISO as inputs*/
   ((volatile struct pio_regs *)AT91_PIOA_BASE)->odr =  PIO(SD_PIN_PROTECT)|
PIO(SD_PIN_PRESENT)|PIO(SD_PIN_MISO);

   /*Timer SPI configuration*/
   tc->rc  = SWSPI_RC  ; //20Khz with 50Mhz clk
   tt->bmr = TC2XC2S(1) | TC1XC1S(1) | TC0XC0S (1); //No external inputs
   tc->cmr = 0x00000000; 
   tc->cmr = TCCLKS(0) | CPCTRG(1) ;
                         //Compare mode
                         //RC Compare trigger enabled 
                         //Clock = MCK/2 on rising edge
   tc->idr = TC_CPCS   ; //Disable Interrupts on RC Compare
   tc->ccr = TC_CLKEN  ; //Enables clock   
   /*Interrupt configuration                         */
   /*By default the timers interrupt are highlevel   */
   /*See /linux-2.4.x/arch/armnommu/mach-atmel/irq.c */
   spin_lock_init(&irq_spi_lock);
   spin_lock(&irq_spi_lock);
   setup_arm_irq(SPI_TIMER_IRQ_NUM, &spi_timer_irq);
   at91_unmask_irq(SPI_TIMER_IRQ_NUM); //Enable AIC interrupt
   spin_unlock(&irq_spi_lock);
   // Variables initialization
   sema_init(&spi_sem,0);
   spi_byte = 0x00;
   
   // Start Clock
   tc->ccr = TC_SWTRG | TC_CLKEN; 
   tc->ccr = TC_CLKEN;

   spi_cs_deassert();
   
   printk(KERN_INFO "SWSPI: Attached at Timer%d (irq = %d)
\n",(4-SPI_TIMER_IRQ_NUM),SPI_TIMER_IRQ_NUM);

   return(0);
}

int spi_send_byte (char byte)
{
  /*SPI timer structures*/
  register volatile struct at91_timers* tt = (struct at91_timers*)
(AT91_TC_BASE);
  register volatile struct at91_timer_channel* tc =
&tt->chans[SPI_TIMER].ch;

  spin_lock(&irq_spi_lock);
  spi_byte = byte & 0xFF;
  tc->ier = TC_CPCS; //Enable interrupt on RC Compare
  spin_unlock(&irq_spi_lock);
  down_interruptible(&spi_sem);
  return(byte);

}

char spi_receive_byte (void)
{

  /*SPI timer structures*/
  register volatile struct at91_timers* tt = (struct at91_timers*)
(AT91_TC_BASE);
  register volatile struct at91_timer_channel* tc =
&tt->chans[SPI_TIMER].ch;

  spin_lock(&irq_spi_lock);
  spi_byte = spi_byte | 0xFF;
  tc->ier = TC_CPCS; //Enable Interrupt on RC Compare
  spin_unlock(&irq_spi_lock);
  down_interruptible(&spi_sem);
  return(spi_byte);
}

static ssize_t  swspi_write (struct file *filp,const char *buf, ssize_t
count,loff_t *f_pos)
{
  
  int i = 0;
  for (i=0; i<count; i++) {
    spi_send_byte(buf[i]);
  }
  return (i);
}

static ssize_t swspi_read (struct file *filp,char *buf, ssize_t count,loff_t
*f_pos)
{
  int i;
  for (i=0; i<count; i++) {
    buf[i] = spi_receive_byte();
  }
  return (i);
}

void spi_cs_assert (void)
{
 ((volatile struct pio_regs *)AT91_PIOA_BASE)->codr =  PIO(SD_PIN_NSS);

}  
void spi_cs_deassert (void)
{
   ((volatile struct pio_regs *)AT91_PIOA_BASE)->sodr =  PIO(SD_PIN_NSS);
}


static void SWSPI_IRQ_Handler (int irq,void *dev_id,struct pt_regs *regs)
{
   static int sent_bits = 0;
   static int irq_count = 0;
   unsigned long sr;
   /*SPI timer structures*/
   register volatile struct at91_timers* tt = (struct at91_timers*)
(AT91_TC_BASE);
   register volatile struct at91_timer_channel* tc =
&tt->chans[SPI_TIMER].ch;
   
   sr = tc->sr; //Read Status register, it's mandatory.
   // Fall edge Clock
   ((volatile struct pio_regs *)AT91_PIOA_BASE)->codr =  PIO(SD_PIN_SCK);
   
   // Set bit to transfer - MSb first
    if (spi_byte & 0x80) {
      ((volatile struct pio_regs *)AT91_PIOA_BASE)->sodr =
PIO(SD_PIN_MOSI);
    }else {
      ((volatile struct pio_regs *)AT91_PIOA_BASE)->codr =
PIO(SD_PIN_MOSI);
    }                                   
 
   // Rise edge Clock
   ((volatile struct pio_regs *)AT91_PIOA_BASE)->sodr =  PIO(SD_PIN_SCK);
        

  // Read incomming bit
 if ((((volatile struct pio_regs *)AT91_PIOA_BASE)->pdsr >> SD_PIN_MISO ) &
0x00000001) {
  spi_byte = (spi_byte << 1) | 0x01;
  } else {
      spi_byte = (spi_byte << 1) & 0xFE;
  }

  sent_bits++;
  irq_count++;

  if (sent_bits == 8){
    spin_lock(&irq_spi_lock);
    sent_bits = 0;
    tc->idr=TC_CPCS; //Disable interrupt on RC Compare
    spin_unlock(&irq_spi_unlock);
    up(&spi_sem);
  }
}

MODULE_AUTHOR ("Ramon Flores <[EMAIL PROTECTED]>");
MODULE_DESCRIPTION ("Software SPI Driver for AT91xx40");
MODULE_LICENSE ("GPL");

module_init (swspi_init);
module_cleanup (cleanup_swspi);


zarlink.h
#include <linux/ioctl.h>

#define ZARLINK_MAJOR 50 
#define ZARLINK_IOC_MAGIC 'k' + ZARLINK_MAJOR

/* GCM Zarlink GigaSwitch Implementation */
#define SWITCH_REG_DEVICE_ACTIVE   0x0FFF
#define SWITCH_REG_READBACK        0x1000
#define SWITCH_REG_ECR1P0          0x0000
#define SWITCH_REG_ECR1P1          0x0002
#define SWITCH_REG_ECR1P2          0x0004
#define SWITCH_REG_ECR1P3          0x0006
#define SWITCH_REG_DPST            0x0F06
#define SWITCH_REG_DTST            0x0F07

#define SWITCH_VAL_CHIP_ON         0xDA
#define SWITCH_VAL_MODULE_DETECTED 0x80
#define SWITCH_VAL_GIGA            0x10
#define SWITCH_VAL_LINK_DOWN       0X08 
#define SWITCH_VAL_FAST            0X04
#define SWITCH_VAL_FULL_DUPLEX     0X02
#define SWITCH_VAL_FLOW_CONTROL    0X01

#define SWITCH_PORT_UP               0X18
#define SWITCH_PORT_DOWN             0x10
#define SWITCH_PORT_DOWN_ZERO        0xF7
#define SWITCH_PORT_FULLDUPLEX       0XFD
#define SWITCH_PORT_HALFDUPLEX       0x02
#define SWITCH_PORT_FLOWCONTROL_ON   0XFE
#define SWITCH_PORT_FLOWCONTROL_OFF  0X01
#define SWITCH_PORT_FLOWCONTROL_SIM  0XD0
#define SWITCH_PORT_FLOWCONTROL_ASIM 0X20


#define SWITCH_PORT_CONF           0xD8
#define SWITCH_PORT0               0X00
#define SWITCH_PORT1               0X01
#define SWITCH_PORT2               0X02
#define SWITCH_PORT3               0X03

#define WAIT_SPI_ACCESS            2

/*Define ZARLINK IOCTLS*/
/* Q means Query - reponse on the return value*/
#define ZARLINK_IOCQACTIVE                 _IO(ZARLINK_IOC_MAGIC,0)
#define ZARLINK_IOCQPORT                   _IO(ZARLINK_IOC_MAGIC,1)
#define ZARLINK_IOCTPORT_UP                _IO(ZARLINK_IOC_MAGIC,2)
#define ZARLINK_IOCTPORT_DOWN              _IO(ZARLINK_IOC_MAGIC,3)
#define ZARLINK_IOCTPORT_FULLDUPLEX        _IO(ZARLINK_IOC_MAGIC,4)
#define ZARLINK_IOCTPORT_HALFDUPLEX        _IO(ZARLINK_IOC_MAGIC,5)
#define ZARLINK_IOCTPORT_FLOWCONTROL_ON    _IO(ZARLINK_IOC_MAGIC,6)
#define ZARLINK_IOCTPORT_FLOWCONTROL_OFF   _IO(ZARLINK_IOC_MAGIC,7)
#define ZARLINK_IOCTPORT_FLOWCONTROL_SIM   _IO(ZARLINK_IOC_MAGIC,8)
#define ZARLINK_IOCTPORT_FLOWCONTROL_ASIM  _IO(ZARLINK_IOC_MAGIC,9)



zarlink.c
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/delay.h>

#include <linux/fs.h>
#include <linux/iobuf.h>
#include <linux/major.h>
#include <linux/blkdev.h>
#include <linux/raw.h>
#include <linux/capability.h> 
#include <linux/smp_lock.h>
#include <asm/uaccess.h>

#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/io.h>

#include <asm/arch/widewlan.h>

#include <linux/zarlink.h>

EXPORT_SYMBOL(zarlink_init);
static int openflag_zarlink = 0;

static int zarlink_ioctl (struct inode *inode, struct file *file,
                          unsigned int cmd, unsigned int arg){
  
  unsigned int byteRead;
  unsigned long inbAddress;
  unsigned long outbAddress;
  unsigned long outbData;
  
  switch(cmd){
  case ZARLINK_IOCQACTIVE:
    byteRead = inb (FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_DEVICE_ACTIVE);
    break;
  case ZARLINK_IOCQPORT:
    switch(arg){
    case SWITCH_PORT0:
      outbData    = SWITCH_PORT0;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DPST;
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DTST;
      break;
    case SWITCH_PORT1:
      outbData    = SWITCH_PORT1;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DPST;
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DTST;
      break;
    case SWITCH_PORT2:
      outbData    = SWITCH_PORT2;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DPST;
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DTST;
      break;
    case SWITCH_PORT3:
      outbData    = SWITCH_PORT3;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DPST;
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DTST;
      break;
    default:
      byteRead = (-ENOTTY);
      return (byteRead);
      break;
    }
    outb (outbData,outbAddress);
    mdelay(WAIT_SPI_ACCESS);
    byteRead = inb ( inbAddress );
    break;
  case ZARLINK_IOCTPORT_UP:
    switch(arg){
    case SWITCH_PORT0:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      break;
    case SWITCH_PORT1:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      break;
    case SWITCH_PORT2:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      break;
    case SWITCH_PORT3:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      break;
    default:
      byteRead = (-ENOTTY);
      return (byteRead);
      break;
    }
     byteRead = inb ( inbAddress );
     mdelay(WAIT_SPI_ACCESS);
     outbData = (byteRead | SWITCH_PORT_UP);
     outb ( outbData , outbAddress);
     mdelay(WAIT_SPI_ACCESS);
     byteRead = inb ( inbAddress );
    break;
    case ZARLINK_IOCTPORT_DOWN:
    switch(arg){
    case SWITCH_PORT0:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      outbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      break;
    case SWITCH_PORT1:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      outbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      break;
    case SWITCH_PORT2:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      outbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      break;
    case SWITCH_PORT3:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      outbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      break;
    default:
      byteRead = (-ENOTTY);
      return (byteRead);
      break;
    }
     byteRead = inb ( inbAddress );
     mdelay(WAIT_SPI_ACCESS);
     outbData = (byteRead | SWITCH_PORT_DOWN) & SWITCH_PORT_DOWN_ZERO;
     outb ( outbData , outbAddress);
     mdelay(WAIT_SPI_ACCESS);
     byteRead = inb ( inbAddress );
    break;
  case ZARLINK_IOCTPORT_FULLDUPLEX:
    switch(arg){
    case SWITCH_PORT0:
      inbAddress  =  FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      outbAddress =  FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      break;
    case SWITCH_PORT1:
      inbAddress  =  FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      outbAddress =  FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
  break;
    case SWITCH_PORT2:
      inbAddress  =  FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      outbAddress =  FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      break;
    case SWITCH_PORT3:
      inbAddress  =  FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      outbAddress =  FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      break;
    default:
      byteRead = (-ENOTTY);
      return (byteRead);
      break;
    }
    byteRead = inb ( inbAddress );
    mdelay(WAIT_SPI_ACCESS);
    outbData = (byteRead | SWITCH_PORT_HALFDUPLEX) & SWITCH_PORT_FULLDUPLEX;
    outb ( outbData , outbAddress);
    mdelay(WAIT_SPI_ACCESS);
    byteRead = inb ( inbAddress );
    break;
  case ZARLINK_IOCTPORT_HALFDUPLEX:
    switch(arg){
    case SWITCH_PORT0:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      break;
    case SWITCH_PORT1:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      break;
    case SWITCH_PORT2:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      break;
    case SWITCH_PORT3:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      break;
    default:
      byteRead = (-ENOTTY);
      return (byteRead);
      break;
    }
    byteRead = inb ( inbAddress );
    mdelay(WAIT_SPI_ACCESS);
    outbData = (byteRead | SWITCH_PORT_HALFDUPLEX);
    outb ( outbData , outbAddress);
    mdelay(WAIT_SPI_ACCESS);
    byteRead = inb ( inbAddress );
    break;
  case ZARLINK_IOCTPORT_FLOWCONTROL_ON:
    switch(arg){
    case SWITCH_PORT0:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      break;
    case SWITCH_PORT1:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      break;
    case SWITCH_PORT2:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      break;
    case SWITCH_PORT3:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      break;
    default:
      byteRead = (-ENOTTY);
      return (byteRead);
      break;
    }
    byteRead = inb ( inbAddress );
    mdelay(WAIT_SPI_ACCESS);
    outbData = (byteRead &  SWITCH_PORT_FLOWCONTROL_ON);
    outb ( outbData , outbAddress);
    mdelay(WAIT_SPI_ACCESS);
    byteRead = inb ( inbAddress );
    break;
  case ZARLINK_IOCTPORT_FLOWCONTROL_OFF:
    switch(arg){
    case SWITCH_PORT0:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      break;
    case SWITCH_PORT1:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      break;
    case SWITCH_PORT2:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      break;
    case SWITCH_PORT3:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      break;
    default:
      byteRead = (-ENOTTY);
      return (byteRead);
      break;
    }
    byteRead = inb ( inbAddress );
    mdelay(WAIT_SPI_ACCESS);
    outbData = (byteRead |  SWITCH_PORT_FLOWCONTROL_OFF);
    outb ( outbData , outbAddress);
    mdelay(WAIT_SPI_ACCESS);
    byteRead = inb ( inbAddress );
    break;
  case ZARLINK_IOCTPORT_FLOWCONTROL_SIM:
    switch(arg){
    case SWITCH_PORT0:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      break;
    case SWITCH_PORT1:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      break;
    case SWITCH_PORT2:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      break;
    case SWITCH_PORT3:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      break;
    default:
      byteRead = (-ENOTTY);
      break;
    }
    byteRead = inb ( inbAddress );
    mdelay(WAIT_SPI_ACCESS);
    outbData = (byteRead &  SWITCH_PORT_FLOWCONTROL_SIM);
    outb ( outbData , outbAddress);
    mdelay(WAIT_SPI_ACCESS);
    byteRead = inb ( inbAddress );
    break;
  case ZARLINK_IOCTPORT_FLOWCONTROL_ASIM:
    switch(arg){
    case SWITCH_PORT0:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P0
; 
      break;
    case SWITCH_PORT1:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P1
;
      break;
    case SWITCH_PORT2:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P2
;
      break;
    case SWITCH_PORT3:
      inbAddress  = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      outbAddress = FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_ECR1P3
;
      break;
    default:
      byteRead = (-ENOTTY);
      break;
    }
    byteRead = inb ( inbAddress );
    mdelay(WAIT_SPI_ACCESS);
    outbData = (byteRead |  SWITCH_PORT_FLOWCONTROL_ASIM);
    outb ( outbData , outbAddress);
    mdelay(WAIT_SPI_ACCESS);
    byteRead = inb ( inbAddress );
    break;
  default:
    byteRead = (-ENOTTY);
    break;
  }
  return(byteRead);
}

/*Not implemented open and release actions, these actions*/
/*are not necessary*/
/*
int zarlink_open (struct inode *inode,struct file *filep){
  return 0;
}

int zarlink_release (struct inode *inode,struct file *filep){
  return 0;
}*/

static int zarlink_open(struct inode *inode, struct file *filp)
{
  if ( openflag_zarlink )
    return -EBUSY;

  MOD_INC_USE_COUNT;
  openflag_zarlink = 1;
  return 0;
}

static int zarlink_release(struct inode *inode, struct file *filp)
{
  openflag_zarlink = 0;
  MOD_DEC_USE_COUNT;
        return 0;
}

static struct file_operations zarlink_fops = {
  //        read:           zarlink_read,
  //        write:          zarlink_write,
          open:           zarlink_open,
          release:        zarlink_release,
          ioctl:          zarlink_ioctl,
};

void cleanup_zarlink (void){
  unregister_chrdev(ZARLINK_MAJOR, "swg");
}

static int __init zarlink_init (void)
{
  
  unsigned char byteRead;
  int result; 
  /* Reset all devices*/
  outw(0x000E,FPGA_ADDR_BASE + SYS_RESETS); 
  outw(0x000C,FPGA_ADDR_BASE + SYS_RESETS);
  mdelay(10);
  outw(0x000E,FPGA_ADDR_BASE + SYS_RESETS);
  mdelay(10);
  outw(0x000C,FPGA_ADDR_BASE + SYS_RESETS);
  outw(0x0008,FPGA_ADDR_BASE + SYS_RESETS);
  outw(0x0000,FPGA_ADDR_BASE + SYS_RESETS);

  /* Set-up Switch Interface*/
  /* 0xD8 -> Link-up at 1Gbps*/
  /* 0x00 Port0, 0x02 Port1, 0x04 Port2, 0x06 Port3*/
  byteRead = inb (FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_DEVICE_ACTIVE);
    if( byteRead == SWITCH_VAL_CHIP_ON){
    /*Register de driver*/
    result = register_chrdev(ZARLINK_MAJOR, "swg", &zarlink_fops);
    if( result < 0 ){
      printk(KERN_INFO "Zarlink: Unable to get %d major\n",ZARLINK_MAJOR);
      return result;
    }

    printk(KERN_INFO "Zarlink MVTX2801A detected\n");
    /* Configure Ports */
    outb (SWITCH_PORT_CONF,FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_ECR1P0 );
    outb (SWITCH_PORT_CONF,FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_ECR1P2 );
    outb (SWITCH_PORT_CONF,FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_ECR1P3 );
    /* Read Status */
    
    /* Port 0 */
    outb (SWITCH_PORT0,FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_DPST);
    byteRead = inb ( FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DTST
);
    if ( byteRead & SWITCH_VAL_MODULE_DETECTED ){
      printk (KERN_INFO "Zarlink Port0 detected : ");
      if ( !(byteRead & SWITCH_VAL_LINK_DOWN) ){
        printk ("Link up , ");
      }else{
        printk ("Link down , ");
      }
      if ( byteRead & SWITCH_VAL_GIGA ){
        printk ("Gigabit Ethernet Mode , ");
      }else if ( byteRead & SWITCH_VAL_FAST ){
        printk ("Fast Ethernet Mode , ");
      }
      if ( byteRead & SWITCH_VAL_FULL_DUPLEX ){
        printk ("Full Duplex  Mode , ");
      }
      if ( byteRead & SWITCH_VAL_FLOW_CONTROL ){
        printk ("Flow Control Enable");
      }
      printk("\n");
    }else{
      printk (KERN_INFO "Zarlink Port0 NOT detected\n");
    }
    
    /* Port 1 */
    outb (SWITCH_PORT1,FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_DPST);
    byteRead = inb ( FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DTST
);
    if ( byteRead & SWITCH_VAL_MODULE_DETECTED ){
      printk (KERN_INFO "Zarlink Port1 detected : ");
      if ( !(byteRead & SWITCH_VAL_LINK_DOWN) ){
        printk ("Link up , ");
      }else{
        printk ("Link down , ");
      }
      if ( byteRead & SWITCH_VAL_GIGA ){
        printk ("Gigabit Ethernet Mode , ");
      }else if ( byteRead & SWITCH_VAL_FAST ){
        printk ("Fast Ethernet Mode , ");
      }
      if ( byteRead & SWITCH_VAL_FULL_DUPLEX ){
        printk ("Full Duplex  Mode , ");
      }
      if ( byteRead & SWITCH_VAL_FLOW_CONTROL ){
        printk ("Flow Control Enable");
      }
      printk("\n");
    }else{
      printk (KERN_INFO "Zarlink Port1 NOT detected\n");
    }
    
    /* Port 2 */
    outb (SWITCH_PORT2,FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_DPST);
    byteRead = inb ( FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DTST
);
    if ( byteRead & SWITCH_VAL_MODULE_DETECTED ){
      printk (KERN_INFO "Zarlink Port2 detected : ");
      if ( !(byteRead & SWITCH_VAL_LINK_DOWN) ){
        printk ("Link up , ");
      }else{
        printk ("Link down , ");
      }
      if ( byteRead & SWITCH_VAL_GIGA ){
        printk ("Gigabit Ethernet Mode , ");
      }else if ( byteRead & SWITCH_VAL_FAST ){
        printk ("Fast Ethernet Mode , ");
      }
      if ( byteRead & SWITCH_VAL_FULL_DUPLEX ){
        printk ("Full Duplex  Mode , ");
      }
      if ( byteRead & SWITCH_VAL_FLOW_CONTROL ){
        printk ("Flow Control Enable");
      }
      printk("\n");
    }else{
      printk (KERN_INFO "Zarlink Port2 NOT detected\n");
    }
    
    /* Port 3 */
    outb (SWITCH_PORT3,FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET +
SWITCH_REG_DPST);
    byteRead = inb ( FPGA_ADDR_BASE + GIGA_SWITCH_OFFSET + SWITCH_REG_DTST
);
    if ( byteRead & SWITCH_VAL_MODULE_DETECTED ){
      printk (KERN_INFO "Zarlink Port3 detected : ");
      if ( !(byteRead & SWITCH_VAL_LINK_DOWN) ){
        printk ("Link up , ");
      }else{
        printk ("Link down , ");
      }
      if ( byteRead & SWITCH_VAL_GIGA ){
        printk ("Gigabit Ethernet Mode , ");
      }else if ( byteRead & SWITCH_VAL_FAST ){
        printk ("Fast Ethernet Mode , ");
      }
      if ( byteRead & SWITCH_VAL_FULL_DUPLEX ){
        printk ("Full Duplex  Mode , ");
      }
      if ( byteRead & SWITCH_VAL_FLOW_CONTROL ){
        printk ("Flow Control Enable");
      }
      printk("\n");
    }else{
      printk (KERN_INFO "Zarlink Port3 NOT detected\n");
    }
  }else{
     printk(KERN_INFO "Zarlink MVTX2801A NOT detected\n");
  }
  
  return (0);
}

MODULE_AUTHOR ("Ramon Flores <[EMAIL PROTECTED]>");
MODULE_DESCRIPTION ("Zarlink Switch GigabitEthernet Driver");
MODULE_LICENSE ("GPL");
//MODULE_PARM_DESC (io,"I/O Base Address");
//MODULE_PARM (io,"i");

module_init (zarlink_init);

Thanks, Ramon


_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to