- 论坛徽章:
- 0
|
好的,与大家共享!
/*网友注意 : PC25 for MDIO in the 8271 of 826x; PC22 for MDC in the 8271 of 826x ;IMMAP_BASE请根据自己的硬件进行修改 */
#define TRUE 1
#define FALSE 0
#define ON 1
#define OFF 0
/*------------------------*/
/* Fundamental Data Types */
/*------------------------*/
typedef char BYTE;
typedef unsigned char UBYTE;
typedef short HWORD;
typedef unsigned short UHWORD;
typedef long WORD;
typedef unsigned long UWORD;
typedef unsigned char BOOL;
typedef volatile char VBYTE;
typedef volatile unsigned char VUBYTE;
typedef volatile short VHWORD;
typedef volatile unsigned short VUHWORD;
typedef volatile long VWORD;
typedef volatile unsigned long VUWORD;
typedef volatile unsigned char VBOOL;
/* CPU base address defination */
#define IMMAP_BASE 0xf0000000
#define IMMAP_LENTH 0x60000
/* The major device number. We can't rely on dynamic
* registration any more, because ioctls need to know
* it. */
#define MAJOR_NUM 100
#define DEVICE_NAME "rtl8305"
/*RTL8305 relevant information */
#define MDIO_PIN_MASK 0x00000040 /* PC25 for MDIO in the 8271 of 826x */
#define MDC_PIN_MASK 0x00000200 /* PC22 for MDC in the 8271 of 826x */
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#ifdef CONFIG_SMP
# define __SMP__
#endif
#include <linux/kernel.h>
#include <linux/module.h> /*for MOD_DEC_USE_COUNT ,etc.*/
#include <linux/init.h> /* for module_init */
#include <asm/errno.h>
#include <asm/immap_8260.h>
#include <linux/fs.h> /*character device definitions*/
#include <linux/wrapper.h> /*for register_chrdev and unregister_chrdev
wrapper for compatibility with future versions*/
#include <asm/uaccess.h> /*for get_user and put_user*/
#include <sys/mman.h>
#if CONFIG_MODVERSIONS==1
# include <linux/modversions.h>
#endif
#ifndef KERNEL_VERSION
# define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif
/***********************/
/* Global Declarations */
/***********************/
volatile immap_t *IMM = (immap_t *)(IMMAP_BASE ); /*IMMAP_BASE; Internal Memory Map base pointer (0x30026000)*/
static int Device_Open = 0;
volatile void Z0_Send( void) //"Z0" during reading
{int j;
//z0 =z0
IMM->im_ioport.iop_pdatc &= ~MDC_PIN_MASK; /* clock fail */
IMM->im_ioport.iop_pdirc &= ~MDIO_PIN_MASK; /* pc25=Input low */
for (j=0; j<10; j++);
IMM->im_ioport.iop_pdatc |= MDC_PIN_MASK; /* clock rise */
IMM->im_ioport.iop_pdirc |= MDIO_PIN_MASK; /* pc25=1 utput high */
IMM->im_ioport.iop_pdatc &= ~MDC_PIN_MASK; /* clock fail */
IMM->im_ioport.iop_pdatc &= ~MDIO_PIN_MASK; /* IO low */
for (j=0; j<10; j++);
IMM->im_ioport.iop_pdatc |= MDC_PIN_MASK; /* clock rise */
} /*end Z0_Send*/
volatile void Idle_Send(void) //z* at end of frame
{
//idle
IMM->im_ioport.iop_pdirc |= MDIO_PIN_MASK; /* pc25=1 utput high */
IMM->im_ioport.iop_pdatc &= ~MDIO_PIN_MASK; /* IO low */
IMM->im_ioport.iop_pdatc |= MDC_PIN_MASK; /* clock rise */
IMM->im_ioport.iop_pdatc &= ~MDC_PIN_MASK; /* clock fail */
} /*end Idle_Send*/
volatile void MdioSend( UWORD txF, int size)
{
UWORD dmask;
int i,j; /* index */
dmask = 1 << (size-1); /* msbit out first */
for ( i = 0; i < size; i++ )
{ /* for "size" bits */
IMM->im_ioport.iop_pdatc &= ~MDC_PIN_MASK; /* clock fall */
if ( txF & dmask )
{ /* output data bit high */
IMM->im_ioport.iop_pdatc |= MDIO_PIN_MASK;
}
else
{ /* output data bit low, >400ns */
IMM->im_ioport.iop_pdatc &= ~MDIO_PIN_MASK;
}
for (j=0; j<10; j++);
IMM->im_ioport.iop_pdatc |= MDC_PIN_MASK; /* clock rise */
for (j=0; j<10; j++);
txF = (UWORD)(txF << 1); /* >160ns */
}
} /* end MdioSend */
volatile UWORD MdioReceive(int size)
{
int i,j;
UWORD rxF=0x0000; /* index */
IMM->im_ioport.iop_pdirc &= ~MDIO_PIN_MASK; /* pc25=0:input */
for ( i = 0; i < size; i++ )
{ /* 16 bits */
IMM->im_ioport.iop_pdatc |= MDC_PIN_MASK; /* clock rise */
if ( IMM->im_ioport.iop_pdatc & MDIO_PIN_MASK )
{ /* if read in a high bit */
rxF = ( (UHWORD)(rxF << 1) | 1 ); /* shift in a one */
}
else
{ /* if read in a low bit */
rxF = ( (UHWORD)(rxF << 1) & ~(UHWORD)1 ); /* shift in a zero */
}
for (j=0; j<10; j++);
IMM->im_ioport.iop_pdatc &= ~MDC_PIN_MASK; /* clock fall */
for (j=0; j<10; j++);
} /* end of for loop */
return (rxF);
} /* end MdioReceive */
/*Prototypes*/
static int rtl8305_open(struct inode *inode, struct file *file);
static int rtl8305_release(struct inode *inode, struct file *file);
static int rtl8305_read(struct file *file,char * buffer, size_t length, loff_t * offset);
static int rtl8305_write(struct file *file,const char * buffer, size_t length, loff_t * offset);
struct file_operations rtl8305_ops = {
.read=rtl8305_read,
.write=rtl8305_write,
.open=rtl8305_open,
.release=rtl8305_release
};
static int rtl8305_open(struct inode *inode, struct file *file)
{
UWORD rxF;
//int fd;
if (Device_Open) return -1;
/*To initialize the PortC registers*/
IMM->im_ioport.iop_podrc &= ~MDIO_PIN_MASK; //0:normal
IMM->im_ioport.iop_podrc &= ~MDC_PIN_MASK;
IMM->im_ioport.iop_pdirc |= MDC_PIN_MASK; // 1 C22 for output
IMM->im_ioport.iop_pdirc |= MDIO_PIN_MASK; //1 C25 for output
IMM->im_ioport.iop_pparc &= ~(0x00000240); //0 C22,PC25 as a general purpose IO
/*read a Rtl8305 register for test*/
MdioSend (0xffffffff,32); //preamble
MdioSend (0x01,2); //start
MdioSend (0x02,2); //read
MdioSend (0x00,5); //PHY0
MdioSend (0x01,5); //PHY0-Reg1
Z0_Send(); //z0 =z0
//read from rtl8305
rxF=MdioReceive(16); //PHY0-1=0x7849
Idle_Send(); //idle
printk(KERN_ALERT"\nIn open() HY0-1(0x7849) =ox%lx\n",rxF);
Device_Open++;
MOD_INC_USE_COUNT;
printk(KERN_ALERT"Device Open(%p,%p)\n",inode,file);
return 0 ;
} /*end rtl8305_open*/
static int rtl8305_read(struct file *file,char * buffer, size_t length, loff_t * offset)
{
char rxBuf[2];
rxBuf[0]=* (buffer++);
rxBuf[1]=* buffer;
MdioSend (0x01,2); //start
MdioSend (0x02,2); //read
MdioSend (rxBuf[0],5); //PHY0
MdioSend (rxBuf[1],5); //PHY0-Reg1
Z0_Send(); //z0 =z0
//read from rtl8305
rxBuf[0]=MdioReceive( ; //PHYx-x=high 8 bits
rxBuf[1]=MdioReceive( ; //PHYx-x=low 8 bits
Idle_Send(); //idle
put_user(rxBuf[0], (--buffer));
put_user(rxBuf[1], (++buffer));
// printk(KERN_ALERT"register of RTL8305 =ox%x.%x \n",rxBuf[0],rxBuf[1]);
return (2);
} /*end rtl8305_read*/
static int rtl8305_write(struct file *file,const char * buffer, size_t length, loff_t * offset)
{
char rxBuf[4];
rxBuf[0]=* (buffer++);
rxBuf[1]=* (buffer++);
rxBuf[3]=* (buffer++);
rxBuf[4]=* (buffer);
buffer--;buffer--;buffer--;
MdioSend (0x01,2); //start
MdioSend (0x01,2); //read
MdioSend (rxBuf[0],5); //PHYx
MdioSend (rxBuf[1],5); //Reg x
MdioSend (0x02,2); //write 10 ,turn around
//write to rtl8305
MdioSend (rxBuf[2], ; //high 8 bits
MdioSend (rxBuf[3], ; //low 8 bits
Idle_Send(); //idle
// printk( KERN_ALERT"\nWriting PHY[%d]_Reg[%d]=ox%x.%x successful.\n",rxBuf[0],rxBuf[1],rxBuf[3],rxBuf[4] );
return (4);
} /*end rtl8305_write*/
static int rtl8305_release(struct inode *inode, struct file *file)
{
printk(KERN_ALERT"Rtl8305 device_release(%p,%p)\n",inode,file);
/* We're now ready for our next caller */
Device_Open --;
MOD_DEC_USE_COUNT;
return 0;
} /*end rtl8305_release*/
/* Initialize the module - Register the character device
*/
static int __init rtl8305_module_init( void )
{ int ret_val;
/* Register the character device (atleast try) */
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &rtl8305_ops);
/* Negative values signify an error */
if (ret_val < 0) {
printk ("%s failed with %d\n",
"Sorry, registering the Rtl8305 device ", ret_val);
return ret_val;
}
printk ("%s The major device number is %d.\n",
"Rtl8305 registeration is a success", MAJOR_NUM);
printk ("mknod %s c %d 0\n", DEVICE_NAME,MAJOR_NUM);
return 0;
} /*end rtl8305_module_init*/
/* Cleanup - unregister the appropriate file from /proc */
static void __exit rtl8305_cleanup_module(void)
{
int ret;
/* Unregister the device */
ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
/* If there's an error, report it */
if (ret < 0)
printk(KERN_ALERT"Error in module_unregister_chrdev: %d\n", ret);
printk(KERN_ALERT"in module_unregister_chrdev: %d\n", ret);
} /*end rtl8305_cleanup_module*/
module_init(rtl8305_module_init);
module_exit(rtl8305_cleanup_module);
MODULE_LICENSE("GPL" ;
MODULE_AUTHOR("by Orien Kan" ;
MODULE_DESCRIPTION("Rtl8305 driver" ; |
|