天天看点

linux 下安装装串口驱动,Linux下安装USB转串口驱动(PL2303)

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include "pl2303.h"

#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"

staticintdebug;

#define PL2303_CLOSING_WAIT (30*HZ)

staticconststructusb_device_id id_table[] = {

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },

{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },

{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },

{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },

{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },

{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },

{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },

{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },

{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },

{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },

{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },

{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },

{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },

{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },

{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },

{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },

{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },

{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },

{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },

{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },

{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },

{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },

{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) },

{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },

{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },

{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },

{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },

{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },

{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },

{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },

{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },

{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },

{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },

{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },

{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },

{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },

{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },

{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },

{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },

{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },

{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },

{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },

{ USB_DEVICE(WINCHIPHEAD_VENDOR_ID, WINCHIPHEAD_USBSER_PRODUCT_ID) },

{ }

};

MODULE_DEVICE_TABLE(usb, id_table);

staticstructusb_driver pl2303_driver = {

.name ="pl2303",

.probe =    usb_serial_probe,

.disconnect =   usb_serial_disconnect,

.id_table = id_table,

.suspend =      usb_serial_suspend,

.resume =       usb_serial_resume,

.no_dynamic_id =    1,

.supports_autosuspend = 1,

};

#define SET_LINE_REQUEST_TYPE       0x21

#define SET_LINE_REQUEST        0x20

#define SET_CONTROL_REQUEST_TYPE    0x21

#define SET_CONTROL_REQUEST     0x22

#define CONTROL_DTR         0x01

#define CONTROL_RTS         0x02

#define BREAK_REQUEST_TYPE      0x21

#define BREAK_REQUEST           0x23

#define BREAK_ON            0xffff

#define BREAK_OFF           0x0000

#define GET_LINE_REQUEST_TYPE       0xa1

#define GET_LINE_REQUEST        0x21

#define VENDOR_WRITE_REQUEST_TYPE   0x40

#define VENDOR_WRITE_REQUEST        0x01

#define VENDOR_READ_REQUEST_TYPE    0xc0

#define VENDOR_READ_REQUEST     0x01

#define UART_STATE          0x08

#define UART_STATE_TRANSIENT_MASK   0x74

#define UART_DCD            0x01

#define UART_DSR            0x02

#define UART_BREAK_ERROR        0x04

#define UART_RING           0x08

#define UART_FRAME_ERROR        0x10

#define UART_PARITY_ERROR       0x20

#define UART_OVERRUN_ERROR      0x40

#define UART_CTS            0x80

enumpl2303_type {

type_0,

type_1,

HX,

};

structpl2303_private {

spinlock_t lock;

wait_queue_head_t delta_msr_wait;

u8 line_control;

u8 line_status;

enumpl2303_type type;

};

staticintpl2303_vendor_read(__u16 value, __u16 index,

structusb_serial *serial, unsignedchar*buf)

{

intres = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),

VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,

value, index, buf, 1, 100);

dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", VENDOR_READ_REQUEST_TYPE,

VENDOR_READ_REQUEST, value, index, res, buf[0]);

returnres;

}

staticintpl2303_vendor_write(__u16 value, __u16 index,

structusb_serial *serial)

{

intres = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),

VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,

value, index, NULL, 0, 100);

dbg("0x%x:0x%x:0x%x:0x%x  %d", VENDOR_WRITE_REQUEST_TYPE,

VENDOR_WRITE_REQUEST, value, index, res);

returnres;

}

staticintpl2303_startup(structusb_serial *serial)

{

structpl2303_private *priv;

enumpl2303_type type = type_0;

unsignedchar*buf;

inti;

buf = kmalloc(10, GFP_KERNEL);

if(buf == NULL)

return-ENOMEM;

if(serial->dev->descriptor.bDeviceClass == 0x02)

type = type_0;

elseif(serial->dev->descriptor.bMaxPacketSize0 == 0x40)

type = HX;

elseif(serial->dev->descriptor.bDeviceClass == 0x00)

type = type_1;

elseif(serial->dev->descriptor.bDeviceClass == 0xFF)

type = type_1;

dbg("device type: %d", type);

for(i = 0; i num_ports; ++i) {

priv = kzalloc(sizeof(structpl2303_private), GFP_KERNEL);

if(!priv)

gotocleanup;

spin_lock_init(&priv->lock);

init_waitqueue_head(&priv->delta_msr_wait);

priv->type = type;

usb_set_serial_port_data(serial->port[i], priv);

}

pl2303_vendor_read(0x8484, 0, serial, buf);

pl2303_vendor_write(0x0404, 0, serial);

pl2303_vendor_read(0x8484, 0, serial, buf);

pl2303_vendor_read(0x8383, 0, serial, buf);

pl2303_vendor_read(0x8484, 0, serial, buf);

pl2303_vendor_write(0x0404, 1, serial);

pl2303_vendor_read(0x8484, 0, serial, buf);

pl2303_vendor_read(0x8383, 0, serial, buf);

pl2303_vendor_write(0, 1, serial);

pl2303_vendor_write(1, 0, serial);

if(type == HX)

pl2303_vendor_write(2, 0x44, serial);

else

pl2303_vendor_write(2, 0x24, serial);

kfree(buf);

return0;

cleanup:

kfree(buf);

for(--i; i >= 0; --i) {

priv = usb_get_serial_port_data(serial->port[i]);

kfree(priv);

usb_set_serial_port_data(serial->port[i], NULL);

}

return-ENOMEM;

}

staticintset_control_lines(structusb_device *dev, u8 value)

{

intretval;

retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),

SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,

value, 0, NULL, 0, 100);

dbg("%s - value = %d, retval = %d", __func__, value, retval);

returnretval;

}

staticvoidpl2303_set_termios(structtty_struct *tty,

structusb_serial_port *port,structktermios *old_termios)

{

structusb_serial *serial = port->serial;

structpl2303_private *priv = usb_get_serial_port_data(port);

unsignedlongflags;

unsignedintcflag;

unsignedchar*buf;

intbaud;

inti;

u8 control;

constintbaud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,

4800, 7200, 9600, 14400, 19200, 28800, 38400,

57600, 115200, 230400, 460800, 614400,

921600, 1228800, 2457600, 3000000, 6000000 };

intbaud_floor, baud_ceil;

intk;

dbg("%s -  port %d", __func__, port->number);

if(!tty_termios_hw_change(tty->termios, old_termios))

return;

cflag = tty->termios->c_cflag;

buf = kzalloc(7, GFP_KERNEL);

if(!buf) {

dev_err(&port->dev,"%s - out of memory.\n", __func__);

*tty->termios = *old_termios;

return;

}

i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),

GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,

0, 0, buf, 7, 100);

dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,

buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);

if(cflag & CSIZE) {

switch(cflag & CSIZE) {

caseCS5:

buf[6] = 5;

break;

caseCS6:

buf[6] = 6;

break;

caseCS7:

buf[6] = 7;

break;

default:

caseCS8:

buf[6] = 8;

break;

}

dbg("%s - data bits = %d", __func__, buf[6]);

}

baud = tty_get_baud_rate(tty);

dbg("%s - baud requested = %d", __func__, baud);

if(baud) {

for(k=0; k

if(baud_sup[k] / baud) {

baud_ceil = baud_sup[k];

if(k==0) {

baud = baud_ceil;

}else{

baud_floor = baud_sup[k-1];

if((baud_ceil % baud)

> (baud % baud_floor))

baud = baud_floor;

else

baud = baud_ceil;

}

break;

}

}

if(baud > 1228800) {

if(priv->type != HX)

baud = 1228800;

elseif(baud > 6000000)

baud = 6000000;

}

dbg("%s - baud set = %d", __func__, baud);

if(baud <= 115200) {

buf[0] = baud & 0xff;

buf[1] = (baud >> 8) & 0xff;

buf[2] = (baud >> 16) & 0xff;

buf[3] = (baud >> 24) & 0xff;

}else{

unsigned tmp = 12*1000*1000*32 / baud;

buf[3] = 0x80;

buf[2] = 0;

buf[1] = (tmp >= 256);

while(tmp >= 256) {

tmp >>= 2;

buf[1] <<= 1;

}

if(tmp > 256) {

tmp %= 256;

}

buf[0] = tmp;

}

}

if(cflag & CSTOPB) {

if((cflag & CSIZE) == CS5) {

buf[4] = 1;

dbg("%s - stop bits = 1.5", __func__);

}else{

buf[4] = 2;

dbg("%s - stop bits = 2", __func__);

}

}else{

buf[4] = 0;

dbg("%s - stop bits = 1", __func__);

}

if(cflag & PARENB) {

if(cflag & PARODD) {

if(cflag & CMSPAR) {

buf[5] = 3;

dbg("%s - parity = mark", __func__);

}else{

buf[5] = 1;

dbg("%s - parity = odd", __func__);

}

}else{

if(cflag & CMSPAR) {

buf[5] = 4;

dbg("%s - parity = space", __func__);

}else{

buf[5] = 2;

dbg("%s - parity = even", __func__);

}

}

}else{

buf[5] = 0;

dbg("%s - parity = none", __func__);

}

i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),

SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,

0, 0, buf, 7, 100);

dbg("0x21:0x20:0:0  %d", i);

spin_lock_irqsave(&priv->lock, flags);

control = priv->line_control;

if((cflag & CBAUD) == B0)

priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);

else

priv->line_control |= (CONTROL_DTR | CONTROL_RTS);

if(control != priv->line_control) {

control = priv->line_control;

spin_unlock_irqrestore(&priv->lock, flags);

set_control_lines(serial->dev, control);

}else{

spin_unlock_irqrestore(&priv->lock, flags);

}

buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;

i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),

GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,

0, 0, buf, 7, 100);

dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,

buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);

if(cflag & CRTSCTS) {

if(priv->type == HX)

pl2303_vendor_write(0x0, 0x61, serial);

else

pl2303_vendor_write(0x0, 0x41, serial);

}else{

pl2303_vendor_write(0x0, 0x0, serial);

}

if(baud)

tty_encode_baud_rate(tty, baud, baud);

kfree(buf);

}

staticvoidpl2303_dtr_rts(structusb_serial_port *port,inton)

{

structpl2303_private *priv = usb_get_serial_port_data(port);

unsignedlongflags;

u8 control;

spin_lock_irqsave(&priv->lock, flags);

if(on)

priv->line_control |= (CONTROL_DTR | CONTROL_RTS);

else

priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);

control = priv->line_control;

spin_unlock_irqrestore(&priv->lock, flags);

set_control_lines(port->serial->dev, control);

}

staticvoidpl2303_close(structusb_serial_port *port)

{

dbg("%s - port %d", __func__, port->number);

usb_serial_generic_close(port);

usb_kill_urb(port->interrupt_in_urb);

}

staticintpl2303_open(structtty_struct *tty,structusb_serial_port *port)

{

structktermios tmp_termios;

structusb_serial *serial = port->serial;

structpl2303_private *priv = usb_get_serial_port_data(port);

intresult;

dbg("%s -  port %d", __func__, port->number);

if(priv->type != HX) {

usb_clear_halt(serial->dev, port->write_urb->pipe);

usb_clear_halt(serial->dev, port->read_urb->pipe);

}else{

pl2303_vendor_write(8, 0, serial);

pl2303_vendor_write(9, 0, serial);

}

if(tty)

pl2303_set_termios(tty, port, &tmp_termios);

dbg("%s - submitting read urb", __func__);

result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);

if(result) {

pl2303_close(port);

return-EPROTO;

}

dbg("%s - submitting interrupt urb", __func__);

result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);

if(result) {

dev_err(&port->dev,"%s - failed submitting interrupt urb,"

" error %d\n", __func__, result);

pl2303_close(port);

return-EPROTO;

}

port->port.drain_delay = 256;

return0;

}

staticintpl2303_tiocmset(structtty_struct *tty,

unsignedintset, unsignedintclear)

{

structusb_serial_port *port = tty->driver_data;

structpl2303_private *priv = usb_get_serial_port_data(port);

unsignedlongflags;

u8 control;

if(!usb_get_intfdata(port->serial->interface))

return-ENODEV;

spin_lock_irqsave(&priv->lock, flags);

if(set & TIOCM_RTS)

priv->line_control |= CONTROL_RTS;

if(set & TIOCM_DTR)

priv->line_control |= CONTROL_DTR;

if(clear & TIOCM_RTS)

priv->line_control &= ~CONTROL_RTS;

if(clear & TIOCM_DTR)

priv->line_control &= ~CONTROL_DTR;

control = priv->line_control;

spin_unlock_irqrestore(&priv->lock, flags);

returnset_control_lines(port->serial->dev, control);

}

staticintpl2303_tiocmget(structtty_struct *tty)

{

structusb_serial_port *port = tty->driver_data;

structpl2303_private *priv = usb_get_serial_port_data(port);

unsignedlongflags;

unsignedintmcr;

unsignedintstatus;

unsignedintresult;

dbg("%s (%d)", __func__, port->number);

if(!usb_get_intfdata(port->serial->interface))

return-ENODEV;

spin_lock_irqsave(&priv->lock, flags);

mcr = priv->line_control;

status = priv->line_status;

spin_unlock_irqrestore(&priv->lock, flags);

result = ((mcr & CONTROL_DTR)       ? TIOCM_DTR : 0)

| ((mcr & CONTROL_RTS)    ? TIOCM_RTS : 0)

| ((status & UART_CTS)    ? TIOCM_CTS : 0)

| ((status & UART_DSR)    ? TIOCM_DSR : 0)

| ((status & UART_RING)   ? TIOCM_RI  : 0)

| ((status & UART_DCD)    ? TIOCM_CD  : 0);

dbg("%s - result = %x", __func__, result);

returnresult;

}

staticintpl2303_carrier_raised(structusb_serial_port *port)

{

structpl2303_private *priv = usb_get_serial_port_data(port);

if(priv->line_status & UART_DCD)

return1;

return0;

}

staticintwait_modem_info(structusb_serial_port *port, unsignedintarg)

{

structpl2303_private *priv = usb_get_serial_port_data(port);

unsignedlongflags;

unsignedintprevstatus;

unsignedintstatus;

unsignedintchanged;

spin_lock_irqsave(&priv->lock, flags);

prevstatus = priv->line_status;

spin_unlock_irqrestore(&priv->lock, flags);

while(1) {

interruptible_sleep_on(&priv->delta_msr_wait);

if(signal_pending(current))

return-ERESTARTSYS;

spin_lock_irqsave(&priv->lock, flags);

status = priv->line_status;

spin_unlock_irqrestore(&priv->lock, flags);

changed = prevstatus ^ status;

if(((arg & TIOCM_RNG) && (changed & UART_RING)) ||

((arg & TIOCM_DSR) && (changed & UART_DSR)) ||

((arg & TIOCM_CD)  && (changed & UART_DCD)) ||

((arg & TIOCM_CTS) && (changed & UART_CTS))) {

return0;

}

prevstatus = status;

}

return0;

}

staticintpl2303_ioctl(structtty_struct *tty,

unsignedintcmd, unsignedlongarg)

{

structserial_struct ser;

structusb_serial_port *port = tty->driver_data;

dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);

switch(cmd) {

caseTIOCGSERIAL:

memset(&ser, 0,sizeofser);

ser.type = PORT_16654;

ser.line = port->serial->minor;

ser.port = port->number;

ser.baud_base = 460800;

if(copy_to_user((void__user *)arg, &ser,sizeofser))

return-EFAULT;

return0;

caseTIOCMIWAIT:

dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);

returnwait_modem_info(port, arg);

default:

dbg("%s not supported = 0x%04x", __func__, cmd);

break;

}

return-ENOIOCTLCMD;

}

staticvoidpl2303_break_ctl(structtty_struct *tty,intbreak_state)

{

structusb_serial_port *port = tty->driver_data;

structusb_serial *serial = port->serial;

u16 state;

intresult;

dbg("%s - port %d", __func__, port->number);

if(break_state == 0)

state = BREAK_OFF;

else

state = BREAK_ON;

dbg("%s - turning break %s", __func__,

state == BREAK_OFF ?"off":"on");

result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),

BREAK_REQUEST, BREAK_REQUEST_TYPE, state,

0, NULL, 0, 100);

if(result)

dbg("%s - error sending break = %d", __func__, result);

}

staticvoidpl2303_release(structusb_serial *serial)

{

inti;

structpl2303_private *priv;

dbg("%s", __func__);

for(i = 0; i num_ports; ++i) {

priv = usb_get_serial_port_data(serial->port[i]);

kfree(priv);

}

}

staticvoidpl2303_update_line_status(structusb_serial_port *port,

unsignedchar*data,

unsignedintactual_length)

{

structpl2303_private *priv = usb_get_serial_port_data(port);

structtty_struct *tty;

unsignedlongflags;

u8 status_idx = UART_STATE;

u8 length = UART_STATE + 1;

u8 prev_line_status;

u16 idv, idp;

idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);

idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);

if(idv == SIEMENS_VENDOR_ID) {

if(idp == SIEMENS_PRODUCT_ID_X65 ||

idp == SIEMENS_PRODUCT_ID_SX1 ||

idp == SIEMENS_PRODUCT_ID_X75) {

length = 1;

status_idx = 0;

}

}

if(actual_length 

return;

spin_lock_irqsave(&priv->lock, flags);

prev_line_status = priv->line_status;

priv->line_status = data[status_idx];

spin_unlock_irqrestore(&priv->lock, flags);

if(priv->line_status & UART_BREAK_ERROR)

usb_serial_handle_break(port);

wake_up_interruptible(&priv->delta_msr_wait);

tty = tty_port_tty_get(&port->port);

if(!tty)

return;

if((priv->line_status ^ prev_line_status) & UART_DCD)

usb_serial_handle_dcd_change(port, tty,

priv->line_status & UART_DCD);

tty_kref_put(tty);

}

staticvoidpl2303_read_int_callback(structurb *urb)

{

structusb_serial_port *port =  urb->context;

unsignedchar*data = urb->transfer_buffer;

unsignedintactual_length = urb->actual_length;

intstatus = urb->status;

intretval;

dbg("%s (%d)", __func__, port->number);

switch(status) {

case0:

break;

case-ECONNRESET:

case-ENOENT:

case-ESHUTDOWN:

dbg("%s - urb shutting down with status: %d", __func__,

status);

return;

default:

dbg("%s - nonzero urb status received: %d", __func__,

status);

gotoexit;

}

usb_serial_debug_data(debug, &port->dev, __func__,

urb->actual_length, urb->transfer_buffer);

pl2303_update_line_status(port, data, actual_length);

exit:

retval = usb_submit_urb(urb, GFP_ATOMIC);

if(retval)

dev_err(&urb->dev->dev,

"%s - usb_submit_urb failed with result %d\n",

__func__, retval);

}

staticvoidpl2303_process_read_urb(structurb *urb)

{

structusb_serial_port *port = urb->context;

structpl2303_private *priv = usb_get_serial_port_data(port);

structtty_struct *tty;

unsignedchar*data = urb->transfer_buffer;

chartty_flag = TTY_NORMAL;

unsignedlongflags;

u8 line_status;

inti;

spin_lock_irqsave(&priv->lock, flags);

line_status = priv->line_status;

priv->line_status &= ~UART_STATE_TRANSIENT_MASK;

spin_unlock_irqrestore(&priv->lock, flags);

wake_up_interruptible(&priv->delta_msr_wait);

if(!urb->actual_length)

return;

tty = tty_port_tty_get(&port->port);

if(!tty)

return;

if(line_status & UART_BREAK_ERROR)

tty_flag = TTY_BREAK;

elseif(line_status & UART_PARITY_ERROR)

tty_flag = TTY_PARITY;

elseif(line_status & UART_FRAME_ERROR)

tty_flag = TTY_FRAME;

dbg("%s - tty_flag = %d", __func__, tty_flag);

if(line_status & UART_OVERRUN_ERROR)

tty_insert_flip_char(tty, 0, TTY_OVERRUN);

if(port->port.console && port->sysrq) {

for(i = 0; i actual_length; ++i)

if(!usb_serial_handle_sysrq_char(port, data[i]))

tty_insert_flip_char(tty, data[i], tty_flag);

}else{

tty_insert_flip_string_fixed_flag(tty, data, tty_flag,

urb->actual_length);

}

tty_flip_buffer_push(tty);

tty_kref_put(tty);

}

staticstructusb_serial_driver pl2303_device = {

.driver = {

.owner =    THIS_MODULE,

.name ="pl2303",

},

.id_table =     id_table,

.usb_driver =       &pl2303_driver,

.num_ports =        1,

.bulk_in_size =     256,

.bulk_out_size =    256,

.open =         pl2303_open,

.close =        pl2303_close,

.dtr_rts =      pl2303_dtr_rts,

.carrier_raised =   pl2303_carrier_raised,

.ioctl =        pl2303_ioctl,

.break_ctl =        pl2303_break_ctl,

.set_termios =      pl2303_set_termios,

.tiocmget =     pl2303_tiocmget,

.tiocmset =     pl2303_tiocmset,

.process_read_urb = pl2303_process_read_urb,

.read_int_callback =    pl2303_read_int_callback,

.attach =       pl2303_startup,

.release =      pl2303_release,

};

staticint__init pl2303_init(void)

{

intretval;

retval = usb_serial_register(&pl2303_device);

if(retval)

gotofailed_usb_serial_register;

retval = usb_register(&pl2303_driver);

if(retval)

gotofailed_usb_register;

printk(KERN_INFO KBUILD_MODNAME": "DRIVER_DESC"\n");

return0;

failed_usb_register:

usb_serial_deregister(&pl2303_device);

failed_usb_serial_register:

returnretval;

}

staticvoid__exit pl2303_exit(void)

{

usb_deregister(&pl2303_driver);

usb_serial_deregister(&pl2303_device);

}

module_init(pl2303_init);

module_exit(pl2303_exit);

MODULE_DESCRIPTION(DRIVER_DESC);

MODULE_LICENSE("GPL");

module_param(debug,bool, S_IRUGO | S_IWUSR);

MODULE_PARM_DESC(debug,"Debug enabled or not");