/*
* spcp8x5 USB to serial adaptor driver
*
* Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)
* Copyright (C) 2006 S1 Corp.
*
* Original driver for 2.6.10 pl2303 driver by
* Greg Kroah-Hartman (greg@kroah.com)
* Changes for 2.6.20 by Harald Klein <hari@vt100.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
/* Version Information */
#define DRIVER_VERSION "v0.04"
#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
static int debug;
#define SPCP8x5_007_VID 0x04FC
#define SPCP8x5_007_PID 0x0201
#define SPCP8x5_008_VID 0x04fc
#define SPCP8x5_008_PID 0x0235
#define SPCP8x5_PHILIPS_VID 0x0471
#define SPCP8x5_PHILIPS_PID 0x081e
#define SPCP8x5_INTERMATIC_VID 0x04FC
#define SPCP8x5_INTERMATIC_PID 0x0204
#define SPCP8x5_835_VID 0x04fc
#define SPCP8x5_835_PID 0x0231
static struct usb_device_id id_table [] = {
{ USB_DEVICE(SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID)},
{ USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
{ USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
{ USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)},
{ USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
struct spcp8x5_usb_ctrl_arg {
u8 type;
u8 cmd;
u8 cmd_type;
u16 value;
u16 index;
u16 length;
};
/* wait 30s before close */
#define SPCP8x5_CLOSING_WAIT (30*HZ)
#define SPCP8x5_BUF_SIZE 1024
/* spcp8x5 spec register define */
#define MCR_CONTROL_LINE_RTS 0x02
#define MCR_CONTROL_LINE_DTR 0x01
#define MCR_DTR 0x01
#define MCR_RTS 0x02
#define MSR_STATUS_LINE_DCD 0x80
#define MSR_STATUS_LINE_RI 0x40
#define MSR_STATUS_LINE_DSR 0x20
#define MSR_STATUS_LINE_CTS 0x10
/* verdor command here , we should define myself */
#define SET_DEFAULT 0x40
#define SET_DEFAULT_TYPE 0x20
#define SET_UART_FORMAT 0x40
#define SET_UART_FORMAT_TYPE 0x21
#define SET_UART_FORMAT_SIZE_5 0x00
#define SET_UART_FORMAT_SIZE_6 0x01
#define SET_UART_FORMAT_SIZE_7 0x02
#define SET_UART_FORMAT_SIZE_8 0x03
#define SET_UART_FORMAT_STOP_1 0x00
#define SET_UART_FORMAT_STOP_2 0x04
#define SET_UART_FORMAT_PAR_NONE 0x00
#define SET_UART_FORMAT_PAR_ODD 0x10
#define SET_UART_FORMAT_PAR_EVEN 0x30
#define SET_UART_FORMAT_PAR_MASK 0xD0
#define SET_UART_FORMAT_PAR_SPACE 0x90
#define GET_UART_STATUS_TYPE 0xc0
#define GET_UART_STATUS 0x22
#define GET_UART_STATUS_MSR 0x06
#define SET_UART_STATUS 0x40
#define SET_UART_STATUS_TYPE 0x23
#define SET_UART_STATUS_MCR 0x0004
#define SET_UART_STATUS_MCR_DTR 0x01
#define SET_UART_STATUS_MCR_RTS 0x02
#define SET_UART_STATUS_MCR_LOOP 0x10
#define SET_WORKING_MODE 0x40
#define SET_WORKING_MODE_TYPE 0x24
#define SET_WORKING_MODE_U2C 0x00
#define SET_WORKING_MODE_RS485 0x01
#define SET_WORKING_MODE_PDMA 0x02
#define SET_WORKING_MODE_SPP 0x03
#define SET_FLOWCTL_CHAR 0x40
#define SET_FLOWCTL_CHAR_TYPE 0x25
#define GET_VERSION 0xc0
#define GET_VERSION_TYPE 0x26
#define SET_REGISTER 0x40
#define SET_REGISTER_TYPE 0x27
#define GET_REGISTER 0xc0
#define GET_REGISTER_TYPE 0x28
#define SET_RAM 0x40
#define SET_RAM_TYPE 0x31
#define GET_RAM 0xc0
#define GET_RAM_TYPE 0x32
/* how come ??? */
#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
enum spcp8x5_type {
SPCP825_007_TYPE,
SPCP825_008_TYPE,
SPCP825_PHILIP_TYPE,
SPCP825_INTERMATIC_TYPE,
SPCP835_TYPE,
};
/* 1st in 1st out buffer 4 driver */
struct ringbuf {
unsigned int buf_size;
char *buf_buf;
char *buf_get;
char *buf_put;
};
/* alloc the ring buf and alloc the buffer itself */
static inline struct ringbuf *alloc_ringbuf(unsigned int size)
{
struct ringbuf *pb;
if (size == 0)
return NULL;
pb = kmalloc(sizeof(*pb), GFP_KERNEL);
if (pb == NULL)
return NULL;
pb->buf_buf = kmalloc(size, GFP_KERNEL);
if (pb->buf_buf == NULL) {
kfree(pb);
return NULL;
}
pb->buf_size = size;
pb->buf_get = pb->buf_put = pb->buf_buf;
return pb;
}
/* free the ring buf and the buffer itself */
static inline void free_ringbuf(struct ringbuf *pb)
{
if (pb != NULL) {
kfree(pb->buf_buf);
kfree(pb);
}
}
/* clear pipo , juest repoint the pointer here */
static inline void clear_ringbuf(struct ringbuf *pb)
{
if (pb != NULL)
pb->buf_get = pb->buf_put;
}
/* get the number of data in the pipo */
static inline unsigned int ringbuf_avail_data(struct ringbuf *pb)
{
if (pb == NULL)
return 0;
return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
}
/* get the number of space in the pipo */
static inline unsigned int ringbuf_avail_space(struct ringbuf *pb)
{
if (pb == NULL)
return 0;
return (pb->buf_size