Regarding USB-to-Serial device driver

Raju Rameshwar Uprade
2010-09-13T09:18:06Z

[-- Attachment #1: Type: text/plain, Size: 2976 bytes --]

> Good.

thanks for appreciation.

> Something wrote it to the driver, did you try it with "debug=1" on the
> modprobe line to see what the driver thinks is happening?

Ya I tried with debug=1 on the modprobe line.

> > f6e80c00 4108452201 C Bo:7:003:2 0 1 >
> > f6e80900 4108453203 C Ii:7:003:1 0:1 10 = a1200000 00000200 0000

same status bytes I am also getting.
One thing I would like to ask why it is coming on Ii (Isochronous endpoint)?

> This was some status bytes coming back, are you sure you got the line
> settings correct?
>
> Your example .c file showed no line settings being set, so you have no
> idea what baud rate you are sending at, or what the flow control is, or
> anything else like that. Please be sure to set that up properly to
> verify that you really are getting the data out to the device properly.
>
Line settings,baud rate, flow control are implemented in mcmdriver.c ( UART driver)
which is attached for your ref.
I am trying to implement functionality of mcmdriver.c in pl2303.c, so that using USB
port I can communicated with various MCM devices connected via RS-485 interface card.
On oscilloscope I have verified that the data is out properly to the device.

output of usbmon :

eebcd000 2366447340 S Co:7:005:0 s 21 22 0003 0000 0000 0
eebcd000 2366449228 C Co:7:005:0 0 0
ee9e1500 2366449269 S Bo:7:005:2 -115 6 = 02110000 0100
ee9e1500 2366450226 C Bo:7:005:2 0 6 >
eebcd700 2366455282 S Co:7:005:0 s 21 22 0000 0000 0000 0
eebcd700 2366456225 C Co:7:005:0 0 0
ef7ebc80 2366456274 S Co:7:005:0 s 21 22 0003 0000 0000 0
ef7ebc80 2366457225 C Co:7:005:0 0 0
ee9e1980 2366458228 C Ii:7:005:1 0:1 10 = a1200000 00000200 1000
ee9e1980 2366458247 S Ii:7:005:1 -115:1 10 <
ee9e1500 2366458358 S Bo:7:005:2 -115 1 = 09
ee9e1500 2366459225 C Bo:7:005:2 0 1 >
eebcdb80 2366459368 S Co:7:005:0 s 21 22 0000 0000 0000 0
ee9e1980 2366460227 C Ii:7:005:1 0:1 10 = a1200000 00000200 0000
ee9e1980 2366460252 S Ii:7:005:1 -115:1 10 <
eebcdb80 2366460256 C Co:7:005:0 0 0
eebcdb80 2366460327 S Co:7:005:0 s 21 22 0003 0000 0000 0
eebcdb80 2366461226 C Co:7:005:0 0 0
ee9e1500 2366461279 S Bo:7:005:2 -115 11 = 00010000 00000000 0000e4
ee9e1500 2366462223 C Bo:7:005:2 0 11 >
eebcdb80 2366472294 S Co:7:005:0 s 21 22 0000 0000 0000 0
eebcdb80 2366474225 C Co:7:005:0 0 0

output of usbmon tell that data going out properly, but it's going in chunks,Ideally It
should go out in one chunk.I think I have to take care of RTS line. UART drivers works
in that way,RTS is enabled for complete data out ,then it is disabled so that we can get
device response.

kindly tell me how and where I can write RTS line enable and disable code in pl2303.c,
so that it can work as mcmdriver.c.

Also today I cross checked usb-to-serial output to the serial port output which I am
getting on MSO. I have also attached output of both in .tif format.It shows that some
last bits are not going out properly thru USB-to-Serial Port.

Kindly help me.

Thanks,

Raj.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mcmdriver.c --]
[-- Type: text/x-csrc; name="mcmdriver.c", Size: 10674 bytes --]

/*************************************************************************
* mcmdriver.c
* Linux kernel module, Serial port driver for MCM communications :
* through RS485 with 9 bit protocol
* requires RS232 / RS485 converter, associated Makefile
*
* under root in a console out of X:
* to install:
* make
* insmod mcmdriver.ko SerialPortNb=1 (or 2)
* mknod /dev/mcmdriver c ... (nbs answered from previous command)
* to uninstall: rmmod mcmdriver , rm -f /dev/mcmdriver
* to check: lsmod
* to test: ./mcmtest.o (compiled from mcmtest.c program)
*
* 20/09/05: modif write9(), no more trans MCM error.
* 01/03/06: modif for Kernel 2.6
* 16/09/2008: modif for FC9 (kernel version 2.6.25.11),it's not working fully but now I m able to get data from the device, there is some bytes lose,have to go thru the code & do the things...
* 23/09/2008: Now the device driver is working fine.I used twisted pair cable instead of single line wire,twisted pair cable reduced the noise level.
**************************************************************************/

//#define __KERNEL__ needed?

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/wait.h>

#include <linux/interrupt.h>
#include <linux/sched.h>
//#include <linux/tqueue.h>
#include <asm/irq.h>
#include <asm/uaccess.h>

#include <asm/serial.h> //for BASE_BAUD
#include <linux/serial_reg.h> //for UART reg
#include <asm/io.h> // or sys/io.h for outb inb
//#include <unistd.h>

MODULE_LICENSE("Dual BSD/GPL");

uint inportb(int port);
void outportb(int port, char value);
void setbit(int port, char bits);
void clrbit(int port, char bits);

char cksum(char *buff);
void ckbaud(void);
void init_baud(unsigned long baud);
static int write9(const char *buff_wr);
irqreturn_t irq_handler(int irq, void *dev_id);
void hw_init(void);

/******************************************************************
* serial write and read functions with MCM
* reading via interruption
******************************************************************/

static char buf_ptr0[200];
static int siz; //must be char for device_read() return value
static int SerialPortNb=0, SerialPortAddr, IRQNb;

DECLARE_WAIT_QUEUE_HEAD(WaitQ);
module_param(SerialPortNb, int, S_IRUGO);

#define UART_IER_DISABLE 0x00 /*disable interrupts, is missing from serial-reg.h*/
#define UART_FCR_DISABLE_FIFO 0x00 /*disable fifo*/
#define UART_FIFO_SETUP (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_1)
#define LCR_ADDR (UART_LCR_WLEN8 | UART_LCR_PARITY | UART_LCR_SPAR)
#define LCR_DATA (UART_LCR_WLEN8 | UART_LCR_PARITY | UART_LCR_SPAR | UART_LCR_EPAR)

/*------------ Macros -----------------------------------------------*/
uint inportb(int port) {return (uint)(inb(SerialPortAddr + port));}
void outportb(int port, char value) {outb(value, SerialPortAddr + port);}
void setbit(int port, char bits) {outportb(port, (inportb(port) | bits));}
void clrbit(int port, char bits) {outportb(port, inportb(port) & ~bits);}

/*---------- CheckSum function----------------------------------------*/
/*char cksum(char *buff)
{
char length, i, cs = 0;

if (siz < 3) return 1;
length = *(buff) + (*(buff+1)<<8);
for(i=0; i<length; i++)
{cs += *(buff+i);}
// printk(KERN_ALERT "cs %d\n", cs);
return cs;
}*/

/*---------- Baud init function--------------------------------------*/
void init_baud(unsigned long baud)
{
unsigned long divisor;
divisor = BASE_BAUD / baud;
printk(KERN_ALERT " I m in BAUD Init function\n");
printk(KERN_ALERT "divisor = %ld\n",divisor);
setbit(UART_LCR,UART_LCR_DLAB);
outportb(UART_DLL,(divisor & 0xff));
outportb(UART_DLM,((divisor >> 8) & 0xff));
clrbit(UART_LCR,UART_LCR_DLAB);
};

/*------------ write function----------------------------------------*/
int write9(const char *buff_wr)
{
int length, i;
// printk(KERN_ALERT "I M IN WRITE9");
length = *(buff_wr+1) + ((*(buff_wr+2))<<8);
setbit(UART_MCR, UART_MCR_RTS); // tx_on
//while (!(inportb(UART_MCR) & UART_MCR_RTS)) {;}
outportb(UART_LCR,LCR_ADDR); // addr parity
//while (!(inportb(UART_LCR) & LCR_ADDR)) {;}
while (!(inportb(UART_LSR) & UART_LSR_THRE)) {;}
outportb(UART_TX, *buff_wr);
while (!(inportb(UART_LSR) & UART_LSR_TEMT)) {;}

outportb(UART_LCR, LCR_DATA); // data parity
//while (!(inportb(UART_LCR) & LCR_DATA)) {;}
for (i=1; i<(length+1); i++) {
while (!(inportb(UART_LSR) & UART_LSR_THRE)) {;}
outportb(UART_TX, *(buff_wr+i));
}
while (!(inportb(UART_LSR) & UART_LSR_TEMT)) {;}
clrbit(UART_MCR, UART_MCR_RTS); // tx_off
//while ((inportb(UART_MCR) & UART_MCR_RTS)) {;}
siz = 0;
/* printk(KERN_ALERT "\nier %.2x\n", inportb(UART_IER));
printk(KERN_ALERT "iir %.2x\n", inportb(UART_IIR));
printk(KERN_ALERT "fcr %.2x\n", inportb(UART_FCR)); */
return 1;
}

/*------------ IRQ handler function-----------------------------------*/
irqreturn_t irq_handler(int irq, void *dev_id)
{
volatile int lsr=0, packsiz=0;

printk(KERN_ALERT "IRQ detected\n");
while(inportb(UART_IIR) & 0x04) {
lsr = inportb(UART_LSR);
if (lsr & 0x02)
{
buf_ptr0[siz] = inportb(UART_RX);
printk(KERN_ALERT "%x ", buf_ptr0[siz]);
} //Overrun

else if (lsr & 0x08)
{
buf_ptr0[siz] = inportb(UART_RX);
printk(KERN_ALERT "Framming Error \n");
printk(KERN_ALERT "%x ", buf_ptr0[siz]);
} //Framing Error
else {
buf_ptr0[siz] = inportb(UART_RX);siz++;
printk(KERN_ALERT "%x ", buf_ptr0[siz-1]);
}
}
if (siz>3) {
packsiz = (*(buf_ptr0+1)+(*(buf_ptr0+2)<<8)+1);
if (siz > 200) {printk(KERN_ALERT "siz error, packet reset\n"); siz = 0;}
else if (siz == packsiz)
wake_up_interruptible(&WaitQ);
}
return IRQ_HANDLED;
}

/*----------- hardware initialisation----------------------------------*/
void hw_init(void)
{
printk(KERN_ALERT "I m in Hw-Init");
outportb(UART_MCR, 0x00);
outportb(UART_IER, UART_IER_DISABLE);
outportb(UART_FCR, UART_FCR_DISABLE_FIFO);
outportb(UART_FCR, UART_FIFO_SETUP);
printk(KERN_ALERT "fcrsetup %.2x\n", UART_FIFO_SETUP);
printk(KERN_ALERT "fcr %.2x\n", inportb(UART_FCR));
outportb(UART_LCR, 0x00);
setbit(UART_MCR, UART_MCR_OUT2 | UART_MCR_RTS); //interrupt enabled
setbit(UART_IER, UART_IER_RDI | UART_IER_THRI| UART_IER_MSI ); // interrupt rx on
// while (!(inportb(UART_IER) & UART_IER_RDI)) {;}

while ((inportb(UART_IIR) & 0x01)==0) {
inportb(UART_LSR);
inportb(UART_MSR);
inportb(UART_RX);
}

init_baud(9600);
}

/******************************************************************
* Module functions for /dev/char driver
* redefines open, write, read and close (release)
******************************************************************/

static dev_t DevNb;
static struct cdev *CharDev; // struct for the internal representation of char devices in the kernel.

static int device_release(struct inode *inode, struct file *file)
{
//release_region(SerialPortNb, 1);
free_irq(IRQNb, NULL);
//MOD_DEC_USE_COUNT;
return 0;
}

static int device_open(struct inode *inode, struct file *file)
{
//if (request_region(SerialPortNb, 1, "mcmdriver") == NULL)
//{printk(KERN_ALERT "Requesting Port failed\n"); return -1;}
// if(request_irq(IRQNb, irq_handler, SA_INTERRUPT, "serial9", NULL))
// {printk(KERN_ALERT "irq request error\n"); return -1;}

printk(KERN_ALERT " I m in device_open function");

if(request_irq(IRQNb, irq_handler, IRQF_DISABLED, "serial9", NULL))

printk(KERN_ALERT " I m in device_open function");

// if(request_irq(IRQNb, irq_handler,IRQF_SHARED , "serial9", NULL))

hw_init();

//MOD_INC_USE_COUNT;

siz = 0;

return 0;
}

static ssize_t device_write(struct file *filp, const char __user *buffer, size_t length, loff_t *offset)
{
write9(buffer);
return 1;
}

/*blocking read with timeout*/
static ssize_t device_read(struct file *filp, char __user *buffer, size_t length, loff_t *offset)
{
int err;//, i;

if (siz < 3)
wait_event_interruptible_timeout(WaitQ, 0,150); // &WaitQ or WaitQ?, 1 or 0?
// wait_event_interruptible(WaitQ,0);
//for (i=0;i<siz;i++) printk(KERN_ALERT "%x ", (unsigned char)buf_ptr0[i]);
//printk(KERN_ALERT "\n");
/*if (cksum(buf_ptr0+1) && (siz > 3)) siz = -1;
else
err = */ copy_to_user(buffer, buf_ptr0, siz);
mdelay(50);
/* Hardware limitation: the driver cannot write 2 times successively in a too short period.
Delay necessary for rewriting just after, optimized for a write & read loop (just 1 printk),
with Set Anl Mask Cmd (the longest) and in a console outside X.
Delay placed here, CS/siz problems if placed before writing ?*/
return siz;
}

static struct file_operations fops = {
.owner = THIS_MODULE,
.open = device_open,
.release = device_release,
.read = device_read,
.write = device_write,
};

static int __init device_init(void)
{
int err;

err = alloc_chrdev_region(&DevNb, 0, 1, "mcmdriver");
if (err < 0)
{printk(KERN_ALERT "Allocating DevNb failed with %d\n", err); return err;}
CharDev = cdev_alloc();
cdev_init(CharDev, &fops);
CharDev->owner = THIS_MODULE;
CharDev->ops = &fops;
err = cdev_add(CharDev, DevNb, 1);
if (err)
{printk(KERN_ALERT "Registering CharDev failed with %d\n", err); return err;}

if (SerialPortNb == 1)
{SerialPortAddr = 0x3f8; IRQNb = 4;}

/* if (SerialPortNb == 1 )
{SerialPortAddr = 0xfe00; IRQNb = 16;} */

/** Changes did for USB to Serial for MCM communication, but lock the computer.......*****/

/**** if (SerialPortNb == 0)
{SerialPortAddr = 0x000; IRQNb = 0;} ***/

else if (SerialPortNb == 2)
{SerialPortAddr = 0x2f8; IRQNb = 3;}
printk(KERN_ALERT "Serial Port %d selected (address %x)\n", SerialPortNb, SerialPortAddr);
printk(KERN_ALERT "Create dev file with 'mknod /dev/mcmdriver c %d %d'.\n", MAJOR(DevNb), MINOR(DevNb));
return 0;
}

static void __exit device_exit(void)
{
cdev_del(CharDev);
unregister_chrdev_region(DevNb, 1);
}

module_init(device_init);
module_exit(device_exit);

[-- Attachment #3: Serial_port_output.tif --]
[-- Type: image/tiff, Size: 41460 bytes --]

[-- Attachment #4: USB-to-serial-port_output.tif --]
[-- Type: image/tiff, Size: 37910 bytes --]