/*
static struct spi_board_info at91sam9x5_spi_devices[] = {
{
.modalias= "spidev",
.max_speed_hz= 1000000,
.bus_num= 0,
.chip_select= 0,
.mode = SPI_MODE_0,
},
};
*/
然后加上如下的代码:
static struct spi_board_info at91sam9x5_spi_devices[] = {
{
.modalias= "sc16is752",
.max_speed_hz= 1000000,
.bus_num= 0,
.chip_select= 0,
.mode = SPI_MODE_0,
.irq = AT91_PIN_PB18,
},
};
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define RHR 0x00 //R
#define THR 0x00 //W
#define IER 0x01
#define FCR 0x02 //R
#define IIR 0x02 //W
#define LCR 0x03
#define MCR 0x04
#define LSR 0x05
#define MSR_1 0x06 //本来是直接定义为MSR的,但是这样定义与汇编指令MSR有冲突
#define SPR 0x07
#define TCR 0x06 //These registers are accessible only when EFR[4] = 1, and MCR[2] = 1
#define TLR 0x07
#define TXLVL 0x08
#define RXLVL 0x09
#define IODIR_752 0x0a
#define IOSTATE 0x0b
#define IOINTENA 0x0c
#define RESERVED 0x0d
#define IOCONTROL 0x0e
#define EFCR 0x0f
//special register The Special Register set is accessible only when LCR[7] = 1 and not 0xBF
#define DLL 0x00
#define DLH 0x01
//enhanced register Enhanced Features Registers are only accessible when LCR = 0xBF
#define EFR 0x02
#define XON1 0x04
#define XON2 0x05
#define XOFF1 0x06
#define XOFF2 0x07
//定义端口
#define channelA 0x0
#define channelB 0x1
//定义spi uart操作幻数
#define SET_channleA _IOW('k', 0, int)
#define SET_channleB _IOW('k', 1, int)
#define SET_STOP_BIT _IOW('k', 2, int)
#define SET_BPS _IOW('k', 3, int)
struct sc16is752_dev {
struct spi_device *spi;
spinlock_t spi_lock;
struct mutex lock;
unsigned char *buf;
unsigned int channel_num;
int irq;
struct work_struct *sc752_irq_work;
wait_queue_head_t sc16is752_q;
unsigned int condition;
};
static struct sc16is752_dev *sc16is752 = NULL;
static char read_752_reg(unsigned int reg, unsigned int channel)
{
struct spi_transfer t[2];
struct spi_message m;
char val = 0;
unsigned char cmd = 0x80 | (reg << 3) | (channel << 1);
spi_message_init(&m);
memset(t, 0, (sizeof t));
t[0].tx_buf = &cmd;
t[0].len = 1;
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = &val;
t[1].len = 1;
spi_message_add_tail(&t[1], &m);
spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &m);
spin_unlock_irq(&sc16is752->spi_lock);
return val;
}
static ssize_t read_channel(int len)
{
#if 0
struct spi_transfer t[2];
struct spi_message m;
unsigned char cmd;
cmd = 0x80 | (THR << 3) | (sc16is752->channel_num<< 1);
printk(KERN_INFO "enter read_channel\n");
spi_message_init(&m);
memset(t, 0, (sizeof t));
t[0].tx_buf = &cmd;
t[0].len = 1;
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = sc16is752->buf;
t[1].len = len;
spi_message_add_tail(&t[1], &m);
spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &m);
spin_unlock_irq(&sc16is752->spi_lock);
printk(KERN_INFO "m.actual_length = %d\n",m.actual_length);
return m.actual_length;
#endif
unsigned int length = 0;
unsigned char status = 0;
do{
status = read_752_reg(LSR, sc16is752->channel_num);
if(status & 0x01)
{
sc16is752->buf[length] = read_752_reg(RHR, sc16is752->channel_num);
length ++;
}
}while(status & 0x01);
return length;
}
static void write_752_reg(unsigned int reg, unsigned int channel, unsigned char data)
{
struct spi_transfer t[2];
struct spi_message m;
char val = data;
unsigned char cmd;
cmd = 0x00 | (reg << 3) | (channel << 1);
spi_message_init(&m);
memset(t, 0, (sizeof t));
t[0].tx_buf = &cmd;
t[0].len = 1;
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = &val;
t[1].len = 1;
spi_message_add_tail(&t[1], &m);
spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &m);
spin_unlock_irq(&sc16is752->spi_lock);
return;
}
static void write_channel(unsigned char *buf, int len)
{
struct spi_transfer t[2];
struct spi_message m;
unsigned char status;
unsigned char cmd;
cmd = 0x00 | (THR << 3) | (sc16is752->channel_num << 1);
status = read_752_reg(LSR, sc16is752->channel_num);
if (status & 0x20)
{
spi_message_init(&m);
memset(t, 0, (sizeof t));
t[0].tx_buf = &cmd;
t[0].len = 1;
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
t[1].len = len;
spi_message_add_tail(&t[1], &m);
spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &m);
spin_unlock_irq(&sc16is752->spi_lock);
}
return;
}
static int sc16is752_open(struct inode *inode, struct file *filp)
{
filp->private_data = sc16is752;
/*initlizate channel A*/
write_752_reg(LCR, channelA, 0x80);
write_752_reg(DLL, channelA, 0x14);
write_752_reg(DLH, channelA, 0x00);
write_752_reg(LCR, channelA, 0xbf);
write_752_reg(EFR, channelA, 0x10);
write_752_reg(LCR, channelA, 0x03);
write_752_reg(IER, channelA, 0x01);
write_752_reg(FCR, channelA, 0xf1);
//write_752_reg(FCR, channelA, 0x51);
write_752_reg(SPR, channelA, 0x41);
write_752_reg(IODIR_752, channelA, 0xff);
write_752_reg(IOSTATE, channelA, 0x00);
/*initlizate channel B*/
write_752_reg(LCR, channelB, 0x80);
write_752_reg(DLL, channelB, 0x14);
write_752_reg(DLH, channelB, 0x00);
write_752_reg(LCR, channelB, 0xbf);
write_752_reg(EFR, channelB, 0x10);
write_752_reg(LCR, channelB, 0x03);
write_752_reg(IER, channelB, 0x01);
write_752_reg(FCR, channelB, 0xf1);
//write_752_reg(FCR, channelB, 0x51);
write_752_reg(SPR, channelB, 0x41);
write_752_reg(IODIR_752, channelB, 0xff);
write_752_reg(IOSTATE, channelB, 0x00);
//request spi buffer
sc16is752->buf = kmalloc(64,GFP_KERNEL);
if(!sc16is752->buf)
{
printk(KERN_INFO "kzallo buf error\n");
return -ENOMEM;
}
nonseekable_open(inode, filp);//设置为不可随机读取。
printk(KERN_INFO "open and initlizate channel A/B succeed\n ");
return 0;
}
static int sc16is752_release(struct inode *inode, struct file *filp)
{
if (NULL != sc16is752->buf)
kfree(sc16is752->buf);
return 0;
}
static long sc16is752_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
unsigned char tmp = 0;
switch (cmd) {
case SET_channleA:
{
sc16is752->channel_num = channelA;
break;
}
case SET_channleB:
{
sc16is752->channel_num = channelB;
break;
}
case SET_STOP_BIT:
{
tmp = read_752_reg(LCR, sc16is752->channel_num);
if(1 == args)
{
tmp &= (~(0x01<<2));//设置1位停止位
write_752_reg(LCR, sc16is752->channel_num, tmp);
}
else if (2 == args)
{
tmp |= (0x01<<2);//设置1.5/2位停止位
write_752_reg(LCR, sc16is752->channel_num, tmp);
}
break;
}
case SET_BPS:
{
tmp = read_752_reg(IER, sc16is752->channel_num);
tmp &= (~(0x01<<4));
//禁止睡眠模式才可以设置波特率。
write_752_reg(IER, sc16is752->channel_num, tmp);
if(9600 == args)
{
write_752_reg(LCR, sc16is752->channel_num, 0x80);
write_752_reg(DLL, sc16is752->channel_num, 0x14);
write_752_reg(DLH, sc16is752->channel_num, 0x00);
write_752_reg(LCR, sc16is752->channel_num, 0xbf);
write_752_reg(EFR, sc16is752->channel_num, 0x10);
write_752_reg(LCR, sc16is752->channel_num, 0x03);
write_752_reg(IER, sc16is752->channel_num, 0x01);
write_752_reg(FCR, sc16is752->channel_num, 0xf1);
write_752_reg(SPR, sc16is752->channel_num, 0x41);
write_752_reg(IODIR_752, sc16is752->channel_num, 0xff);
write_752_reg(IOSTATE, sc16is752->channel_num, 0x00);
}
else if(19200 == args)
{
write_752_reg(LCR, sc16is752->channel_num, 0x80);
write_752_reg(DLL, sc16is752->channel_num, 0x0a);
write_752_reg(DLH, sc16is752->channel_num, 0x00);
write_752_reg(LCR, sc16is752->channel_num, 0xbf);
write_752_reg(EFR, sc16is752->channel_num, 0x10);
write_752_reg(LCR, sc16is752->channel_num, 0x03);
write_752_reg(IER, sc16is752->channel_num, 0x01);
write_752_reg(FCR, sc16is752->channel_num, 0xf1);
write_752_reg(SPR, sc16is752->channel_num, 0x41);
write_752_reg(IODIR_752, sc16is752->channel_num, 0xff);
write_752_reg(IOSTATE, sc16is752->channel_num, 0x00);
}
else if(38400 == args)
{
write_752_reg(LCR, sc16is752->channel_num, 0x80);
write_752_reg(DLL, sc16is752->channel_num, 0x05);
write_752_reg(DLH, sc16is752->channel_num, 0x00);
write_752_reg(LCR, sc16is752->channel_num, 0xbf);
write_752_reg(EFR, sc16is752->channel_num, 0x10);
write_752_reg(LCR, sc16is752->channel_num, 0x03);
write_752_reg(IER, sc16is752->channel_num, 0x01);
write_752_reg(FCR, sc16is752->channel_num, 0xf1);
write_752_reg(SPR, sc16is752->channel_num, 0x41);
write_752_reg(IODIR_752, sc16is752->channel_num, 0xff);
write_752_reg(IOSTATE, sc16is752->channel_num, 0x00);
}
break;
}
default:
break;
}
return 0;
}
static ssize_t sc16is752_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
struct sc16is752_dev *sc16is752 = filp->private_data;
int length = 0;
int missing;
//wait_event(sc16is752->sc16is752_q,sc16is752->condition);//用此函数会导致进程杀不死。
wait_event_interruptible(sc16is752->sc16is752_q,sc16is752->condition);
mutex_lock(&sc16is752->lock);
length = read_channel(size);
missing = copy_to_user(buf, sc16is752->buf, length);
if (missing == length)
length = -EFAULT;
else
length = length - missing;
mutex_unlock(&sc16is752->lock);
sc16is752->condition = 0;
return length;
}
static ssize_t sc16is752_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
int missing ;
struct sc16is752_dev *sc16is752 = filp->private_data;
if(size > 64)
return -EMSGSIZE;
mutex_lock(&sc16is752->lock);
missing = copy_from_user(sc16is752->buf, buf, size);
write_channel(sc16is752->buf, size);
mutex_unlock(&sc16is752->lock);
return 0;
}
struct file_operations sc16is752_fops = {
.owner = THIS_MODULE,
.open = sc16is752_open,
.write = sc16is752_write,
.read = sc16is752_read,
.unlocked_ioctl = sc16is752_ioctl,
.release = sc16is752_release,
};
struct miscdevice sc16is752_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sc16is752",
.fops = &sc16is752_fops,
};
void sc752_work_func(struct work_struct *work)
{
unsigned char tmp = 0;
tmp = read_752_reg(IIR, sc16is752->channel_num);
printk(KERN_INFO "enter sc752_work_func\n");
if(tmp & 0x04)
{
sc16is752->condition = 1;
wake_up(&sc16is752->sc16is752_q);
}
}
irqreturn_t sc16is752_handler(int irq, void *dev_id)
{
schedule_work(sc16is752->sc752_irq_work);
printk(KERN_INFO "enter sc16is752_handler\n");
return IRQ_HANDLED;
}
static int sc16is752_probe(struct spi_device *spi)
{
int ret = 0;
//printk(KERN_INFO "Spi device sc16is752 is probed!\n");
sc16is752 = kzalloc(sizeof(*sc16is752), GFP_KERNEL);
if (!sc16is752)
return -ENOMEM;
sc16is752->channel_num = channelA;//默认使用channelA
sc16is752->buf = NULL;
sc16is752->irq = spi->irq; //中断
sc16is752->spi = spi;
spin_lock_init(&sc16is752->spi_lock);
mutex_init(&sc16is752->lock);
ret = misc_register(&sc16is752_misc);
if (ret != 0) {
printk(KERN_INFO "cannot register miscdev err = %d\n", ret);
}
//printk(KERN_INFO "sc16is752->irq %d\n",sc16is752->irq);
ret = request_threaded_irq(sc16is752->irq, NULL, sc16is752_handler,
IRQF_TRIGGER_FALLING, "sc16is752", NULL);
if (ret < 0 )
{
printk(KERN_INFO "Failed to request IRQ!\n");
}
sc16is752->sc752_irq_work = kzalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(sc16is752->sc752_irq_work, sc752_work_func);
init_waitqueue_head(&sc16is752->sc16is752_q);
sc16is752->condition = 0;//初始化等待条件为0
spi_set_drvdata(spi, sc16is752);
return 0;
}
static int __devexit sc16is752_remove(struct spi_device *spi)
{
misc_deregister(&sc16is752_misc);
free_irq(sc16is752->irq,NULL);
kfree(sc16is752);
return 0;
}
static struct spi_driver sc16is752_driver = {
.driver = {
.name = "sc16is752",
.owner = THIS_MODULE,
},
.probe = sc16is752_probe,
.remove = __devexit_p(sc16is752_remove),
};
static int __init sc16is752_init(void)
{
return spi_register_driver(&sc16is752_driver);
}
static void __exit sc16is752_exit(void)
{
spi_unregister_driver(&sc16is752_driver);
}
module_init(sc16is752_init);
module_exit(sc16is752_exit);
MODULE_DESCRIPTION("Driver for most SPI SC16IS752");
MODULE_AUTHOR("tianyu");
MODULE_LICENSE("GPL");
MODULE_ALIAS("sct");
上面代码注册了一个spi驱动,然后注册一个混杂设备驱动,实现了常用的系统调用。代码运行成功后,会在板子的/dev/目录下,生成一个sc16is752设备文件。打开该设备,是进行设备的初始化,将752设置为中断模式、1位停止位、波特率9600、无奇偶校验、8位数据位。
struct sc16is752_dev {
struct spi_device *spi;//用于存放spi设备结构
spinlock_t spi_lock;//定义自旋锁
struct mutex lock;//互斥锁
unsigned char *buf;//spi设备缓冲区,之后会申请为64字节
unsigned int channel_num;//设备的通道号,表示我要操作那个通道
int irq;//中断号
struct work_struct *sc752_irq_work;//工作队列
wait_queue_head_t sc16is752_q;//进程等待队列
unsigned int condition;//唤醒条件
};
static int sc16is752_probe(struct spi_device *spi)
{
int ret = 0;
//printk(KERN_INFO "Spi device sc16is752 is probed!\n");
sc16is752 = kzalloc(sizeof(*sc16is752), GFP_KERNEL);
if (!sc16is752)
return -ENOMEM;
sc16is752->channel_num = channelA;//默认使用channelA
sc16is752->buf = NULL;
sc16is752->irq = spi->irq; //中断
sc16is752->spi = spi;
spin_lock_init(&sc16is752->spi_lock);
mutex_init(&sc16is752->lock);
ret = misc_register(&sc16is752_misc);
if (ret != 0) {
printk(KERN_INFO "cannot register miscdev err = %d\n", ret);
}
//printk(KERN_INFO "sc16is752->irq %d\n",sc16is752->irq);
ret = request_threaded_irq(sc16is752->irq, NULL, sc16is752_handler,
IRQF_TRIGGER_FALLING, "sc16is752", NULL);
if (ret < 0 )
{
printk(KERN_INFO "Failed to request IRQ!\n");
}
sc16is752->sc752_irq_work = kzalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(sc16is752->sc752_irq_work, sc752_work_func);
init_waitqueue_head(&sc16is752->sc16is752_q);
sc16is752->condition = 0;//初始化等待条件为0
spi_set_drvdata(spi, sc16is752);
return 0;
}
struct miscdevice sc16is752_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sc16is752",
.fops = &sc16is752_fops,
};
struct file_operations sc16is752_fops = {
.owner = THIS_MODULE,
.open = sc16is752_open,
.write = sc16is752_write,
.read = sc16is752_read,
.unlocked_ioctl = sc16is752_ioctl,
.release = sc16is752_release,
};
write_752_reg(DLL, sc16is752->channel_num, 0x14);
write_752_reg(DLH, sc16is752->channel_num, 0x00);
write_752_reg(LCR, sc16is752->channel_num, 0x80);
write_752_reg(DLL, sc16is752->channel_num, 0x14);//设置波特率。
write_752_reg(DLH, sc16is752->channel_num, 0x00);
write_752_reg(LCR, sc16is752->channel_num, 0xbf);
write_752_reg(EFR, sc16is752->channel_num, 0x10);
write_752_reg(LCR, sc16is752->channel_num, 0x03);
write_752_reg(IER, sc16is752->channel_num, 0x01);
write_752_reg(FCR, sc16is752->channel_num, 0xf1);
write_752_reg(SPR, sc16is752->channel_num, 0x41);
write_752_reg(IODIR_752, sc16is752->channel_num, 0xff);
write_752_reg(IOSTATE, sc16is752->channel_num, 0x00);
static ssize_t sc16is752_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
int missing ;
struct sc16is752_dev *sc16is752 = filp->private_data;
if(size > 64)
return -EMSGSIZE;
mutex_lock(&sc16is752->lock);
missing = copy_from_user(sc16is752->buf, buf, size);
write_channel(sc16is752->buf, size);
mutex_unlock(&sc16is752->lock);
return 0;
}
static void write_channel(unsigned char *buf, int len)
{
struct spi_transfer t[2];
struct spi_message m;
unsigned char status;
unsigned char cmd;
cmd = 0x00 | (THR << 3) | (sc16is752->channel_num << 1);
status = read_752_reg(LSR, sc16is752->channel_num);
if (status & 0x20)
{
spi_message_init(&m);
memset(t, 0, (sizeof t));
t[0].tx_buf = &cmd;
t[0].len = 1;
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
t[1].len = len;
spi_message_add_tail(&t[1], &m);
spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &m);
spin_unlock_irq(&sc16is752->spi_lock);
}
return;
}
static ssize_t sc16is752_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
struct sc16is752_dev *sc16is752 = filp->private_data;
int length = 0;
int missing;
//wait_event(sc16is752->sc16is752_q,sc16is752->condition);//用此函数会导致进程杀不死。
wait_event_interruptible(sc16is752->sc16is752_q,sc16is752->condition);
mutex_lock(&sc16is752->lock);
length = read_channel(size);
missing = copy_to_user(buf, sc16is752->buf, length);
if (missing == length)
length = -EFAULT;
else
length = length - missing;
mutex_unlock(&sc16is752->lock);
sc16is752->condition = 0;
return length;
}
Read_channel函数,非常纠结的函数!!
static ssize_t read_channel(int len)
{
#if 0
struct spi_transfer t[2];
struct spi_message m;
unsigned char cmd;
cmd = 0x80 | (THR << 3) | (sc16is752->channel_num<< 1);
printk(KERN_INFO "enter read_channel\n");
spi_message_init(&m);
memset(t, 0, (sizeof t));
t[0].tx_buf = &cmd;
t[0].len = 1;
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = sc16is752->buf;
t[1].len = len;
spi_message_add_tail(&t[1], &m);
spin_lock_irq(&sc16is752->spi_lock);
spi_sync(sc16is752->spi, &m);
spin_unlock_irq(&sc16is752->spi_lock);
printk(KERN_INFO "m.actual_length = %d\n",m.actual_length);
return m.actual_length;
#endif
unsigned int length = 0;
unsigned char status = 0;
do{
status = read_752_reg(LSR, sc16is752->channel_num);
if(status & 0x01)
{
sc16is752->buf[length] = read_752_reg(RHR, sc16is752->channel_num);
length ++;
}
}while(status & 0x01);
return length;
}
当时想一次性把数据读取出来,这样效率快啊,可是,并不知道串口发了多少字节的数据来,所以也无法正确的把接收到的字节长度传送到应用空间。应用空间读取的数据就会是这样:
nand erase 0x200000 0x300000
nand write 0x22000000 0x200000 0x300000
附测试代码:
#include
#include
#include
#include
#include
#define SC752 "/dev/sc16is752"
#define SET_channleA _IOW('k', 0, int)
#define SET_channleB _IOW('k', 1, int)
#define SET_STOP_BIT _IOW('k', 2, int)
#define SET_BPS _IOW('k', 3, int)
#define STOP_BIT_1 0x01
#define STOP_BIT_2 0x02
/**************************************************/
/* 说明:752可以设置1 1.5 2 位停止位,默认设置为1个停止位,字长度默认为8,且不可修改 */
/* 默认波特率设置为9600 */
/* 0-1个停止位(字长度=5,6,7,8) */
/* 1.5个停止位(字长度=5)*/
/* 2个停止位 */
/**************************************************/
int main(void)
{
char buf[64] = {0};
int length = 0;
int i = 0;
int fd = open(SC752, O_RDWR);
if (fd < 0) {
printf("Open %s failure.\n", SC752);
return -1;
}
int rate;
char c;
while(1)
{
/*默认是通道A,波特率9600,停止位1位*/
printf("this is default test,stop bit is 1,Baud rate is 9600\n");
write(fd, "hello", 6);
sleep(1);
length = read(fd, buf, 30);
printf("read length %d. read spi_uart is :%s\n",length, buf);
memset(buf, 0, 64);
sleep(1);
}
#if 0
/*设置通道测试*/
printf("then test set channel,please input a or b\n");
scanf("%c", &c);
if (c == 'a')
{
ioctl(fd, SET_channleA);
}
else if(c == 'b')
{
ioctl(fd, SET_channleB);
}
write(fd, "hello", 6);
sleep(1);
length = read(fd, buf, 30);
printf("read length %d. read spi_uart is :%s\n",length, buf);
memset(buf, 0, 64);
sleep(1);
/*设置停止位测试*/
printf("then test set stop bits,please input 1 or 2");
scanf("%d", &c);
if(c == 1)
{
ioctl(fd, SET_STOP_BIT, STOP_BIT_1);
}
else if(c == 2)
{
ioctl(fd, SET_STOP_BIT, STOP_BIT_2);
}
write(fd, "hello", 6);
sleep(1);
length = read(fd, buf, 30);
printf("read length %d. read spi_uart is :%s\n",length, buf);
memset(buf, 0, 64);
sleep(1);
while(1)
{
/*设置波特率测试,设置波特率之后,停止位变为默认的1位,*/
printf("then test set baud rate,please input 9600 19200 or 38400\n");
scanf("%d", &rate);
ioctl(fd, SET_BPS, rate);
write(fd, "hello", 6);
sleep(1);
length = read(fd, buf, 30);
printf("read length %d\n",length);
for(i = 0;i