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