Re: [PATCH] usb:serial: Add Fintek F81532/534 driver

2016-05-30 Thread Peter Hung

Hi,

Ji-Ze Hong (Peter Hong) 於 2016/5/31 上午 09:33 寫道:

This driver is for Fintek F81532/F81534 USB to Serial Ports IC.



Sorry, I forgot to change the mail title for "PATCH V9". I'll resend a
patch with title "PATCH V9".

Thanks
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 1/1] usb:serial: Add Fintek F81532/534 driver

2016-01-27 Thread Peter Hung
This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

F81532 spec:
https://drive.google.com/file/d/0B8vRwwYO7aMFOTRRMmhWQVNvajQ/view?usp=sharing

F81534 spec:
https://drive.google.com/file/d/0B8vRwwYO7aMFV29pQWJqbVBNc00/view?usp=sharing

F81438 transceiver spec:
http://www.alldatasheet.com/datasheet-pdf/pdf/459082/FINTEK/F81438.html

Features:
1. F81532 is 1-to-2 & F81534 is 1-to-4 serial ports IC
2. Support Baudrate from B50 to B150 (excluding B100).
3. The RTS signal can do auto-direction control by user-space tool.
4. The 4x3 output-only open-drain pins for F81532/534 is designed for
   control outer devices (with our EVB for examples, the 4 sets of pins
   are designed to control transceiver mode). It's also controlled by
   user-space tool.
5. User-space tool will save the configuration in internal storage and
   the IC will read it when power on or driver loaded.

   Please reference https://bitbucket.org/hpeter/fintek-general/src/
   with f81534/tools to get user-space tool to change F81532/534
   setting. Please use it carefully.

Signed-off-by: Peter Hung 
---
Changelog:
v8
1. Remove driver mode GPIOLIB & RS485 control support, the driver will
   only load GPIO/UART Mode when driver attach() & port_probe().
2. Add more documents for 3 generation IC with f81534_calc_num_ports().
3. Simplify the GPIO register structure "f81534_pin_control".
4. Change all counter type from int to size_t.
5. Change some failed message with failed: "status code" and remove all
   exclamation mark in messages.
6. Change all save blocks to block0 due to the driver is only used 1
   block (block0) to save data.
7. Change read MSR in open() instead of port_probe().
8. use GFP_ATOMIC kmalloc mode in write().
9. Maintain old style with 1 read URBs and 4 write URBs like mxuports.c
   I had tested with submit 4 read URBs, but it'll make some port freeze
   when doing BurnInTest Port test.
v7
1. Make all gpiolib function with #ifdef CONFIG_GPIOLIB marco block.
   Due to F81532/534 could run without gpiolib, we implements
   f81534_prepare_gpio()/f81534_release_gpio() always success without
   CONFIG_GPIOLIB.
2. Fix crash when receiving MSR change on driver load/unload. It's cause
   by f81534_process_read_urb() get read URB callback data, but port
   private data is not init complete or released. We solve with 2
   modifications.

   1. add null pointer check with f81534_process_read_urb(). We'll skip
  this report when port_priv = NULL.
   2. when "one" port f81534_port_remove() is called, kill the port-0
  read URB before kfree port_priv.

v6
1. Re-implement the write()/resume() function. Due to this device cant be
   suitable with generic write(), we'll do the submit write URB when
   write()/received tx empty/set_termios()/resume()
2. Logic/Phy Port mapping rewrite in f81534_port_probe() &
   f81534_phy_to_logic_port().
3. Introduced "Port Hide" function. Some customer use F81532 reference
   design for HW layout, but really use F81534 IC. We'll check
   F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do
   port hide with port not used. It can be avoid end-user to use not
   layouted port.
4. The 4x3 output-only open-drain pins for F81532/534 is designed for
   control outer devices (with our EVB for examples, the 4 sets of pins
   are designed to control transceiver mode). So we decide to implement
   with gpiolib interface.
5. Add device vendor id with 0x2c42

v5
1. Change f81534_port_disable/enable() from H/W mode to S/W mode
   It'll skip all rx data when port is not opened.
2. Some function modifier add with static (Thanks for Paul Bolle)
3. It's will direct return when count=0 in f81534_write() to
   reduce spin_lock usage.

v4
1. clearify f81534_process_read_urb() with
   f81534_process_per_serial_block(). (referenced from mxuport.c)
2. We limited f81534_write() max tx kfifo with 124Bytes.
   Original subsystem is designed for auto tranmiting fifo data
   if available. But we must wait for tx_empty for next tx data
   (H/W design).

   With this kfifo size limit, we can use generic subsystem api with
   f81534_write(). When usb_serial_generic_write_start() called after
   first write URB complete, the fifo will no data. The generic
   subsystem of write will go to idle state. Until we received
   TX_EMPTY and release write spinlock, the fifo will fill max
   124Bytes by following f81534_write().

v3
1. Migrate read, write and some routine from custom code to usbserial
   subsystem callback function.
2. Use more defines to replece magic numbers to make it meaningful
3. Make more comments as document in source code.

v2
1. v1 versio

[PATCH V7 1/1] usb:serial: Add Fintek F81532/534 driver

2015-12-01 Thread Peter Hung
This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

Features:
1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
2. Support Baudrate from B50 to B150 (excluding B100).
3. The RTS signal can be transformed their behavior with
   configuration by ioctl TIOCGRS485/TIOCSRS485

   If the driver setting with SER_RS485_ENABLED, the RTS signal will
   high with not in TX and low with in TX.

   If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
   the RTS signal will low with not in TX and high with in TX.

4. The 4x3 output-only open-drain pins for F81532/534 is designed for
   control outer devices (with our EVB for examples, the 4 sets of pins
   are designed to control transceiver mode). So it implements as
   gpiolib interface with output-only function.
5. It'll save the configuration in internal storage when uart/pins mode
   changed.

   Please reference https://bitbucket.org/hpeter/fintek-general/src/
   with f81534/tools to get set_gpio.c & set_mode.c to change F81532/534
   setting. Please use it carefully.

Signed-off-by: Peter Hung 
---
Changelog:
v7
1. Make all gpiolib function with #ifdef CONFIG_GPIOLIB marco block.
   Due to F81532/534 could run without gpiolib, we implements
   f81534_prepare_gpio()/f81534_release_gpio() always success without
   CONFIG_GPIOLIB.
2. Fix crash when receiving MSR change on driver load/unload. It's cause
   by f81534_process_read_urb() get read URB callback data, but port
   private data is not init complete or released. We solve with 2
   modifications.

   1. add null pointer check with f81534_process_read_urb(). We'll skip
  this report when port_priv = NULL.
   2. when "one" port f81534_port_remove() is called, kill the port-0
  read URB before kfree port_priv.

v6
1. Re-implement the write()/resume() function. Due to this device cant be
   suitable with generic write(), we'll do the submit write URB when
   write()/received tx empty/set_termios()/resume()
2. Logic/Phy Port mapping rewrite in f81534_port_probe() &
   f81534_phy_to_logic_port().
3. Introduced "Port Hide" function. Some customer use F81532 reference
   design for HW layout, but really use F81534 IC. We'll check
   F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do
   port hide with port not used. It can be avoid end-user to use not
   layouted port.
4. The 4x3 output-only open-drain pins for F81532/534 is designed for
   control outer devices (with our EVB for examples, the 4 sets of pins
   are designed to control transceiver mode). So we decide to implement
   with gpiolib interface.
5. Add device vendor id with 0x2c42

v5
1. Change f81534_port_disable/enable() from H/W mode to S/W mode
   It'll skip all rx data when port is not opened.
2. Some function modifier add with static (Thanks for Paul Bolle)
3. It's will direct return when count=0 in f81534_write() to
   reduce spin_lock usage.

v4
1. clearify f81534_process_read_urb() with
   f81534_process_per_serial_block(). (referenced from mxuport.c)
2. We limited f81534_write() max tx kfifo with 124Bytes.
   Original subsystem is designed for auto tranmiting fifo data
   if available. But we must wait for tx_empty for next tx data
   (H/W design).

   With this kfifo size limit, we can use generic subsystem api with
   f81534_write(). When usb_serial_generic_write_start() called after
   first write URB complete, the fifo will no data. The generic
   subsystem of write will go to idle state. Until we received
   TX_EMPTY and release write spinlock, the fifo will fill max
   124Bytes by following f81534_write().

v3
1. Migrate read, write and some routine from custom code to usbserial
   subsystem callback function.
2. Use more defines to replece magic numbers to make it meaningful
3. Make more comments as document in source code.

v2
1. v1 version submit to staging tree, but Greg KH advised me to
   cleanup source code & re-submit it to correct subsystem
2. Remove all custom ioctl commands

 drivers/usb/serial/Kconfig  |   10 +
 drivers/usb/serial/Makefile |1 +
 drivers/usb/serial/f81534.c | 2945 +++
 3 files changed, 2956 insertions(+)
 create mode 100644 drivers/usb/serial/f81534.c

diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 56ecb8b..0642864 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -255,6 +255,16 @@ config USB_SERIAL_F81232
  To compile this driver as a module, choose M here: the
  module will be called f81232.
 
+config USB_SERIAL_F8153X
+   tristate "USB Fintek F81532/534 Multi-Ports Serial Driver"
+   help
+ Say Y here if you want to use the Fintek F81532/53

Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver

2015-11-04 Thread Peter Hung
Hi

Peter Hung 於 2015/11/3 上午 11:51 寫道:
> This driver is for Fintek F81532/F81534 USB to Serial Ports IC.
> Changelog:
> v6
>  1. Re-implement the write()/resume() function. Due to this device cant be
> suitable with generic write(), we'll do the submit write URB when
> write()/received tx empty/set_termios()/resume()
>  2. Logic/Phy Port mapping rewrite in f81534_port_probe() &
> f81534_phy_to_logic_port().
>  3. Introduced "Port Hide" function. Some customer use F81532 reference
> design for HW layout, but really use F81534 IC. We'll check
> F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do
> port hide with port not used. It can be avoid end-user to use not
> layouted port.
>  4. The 4x3 output-only open-drain pins for F81532/534 is designed for
> control outer devices (with our EVB for examples, the 4 sets of pins
> are designed to control transceiver mode). So we decide to implement
> with gpiolib interface.

I need to do some improvements with senior advices, so I'll send
v7 patch when I modify & re-test the code complete.

Could you give me some roughly advices of this patch when you having
time.

Thanks for your help
-- 
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver

2015-11-04 Thread Peter Hung

Hi,

Oliver Neukum 於 2015/11/4 下午 04:38 寫道:

On Wed, 2015-11-04 at 16:19 +0800, Peter Hung wrote:

Hi

Oliver Neukum 於 2015/11/3 下午 06:03 寫道:

On Tue, 2015-11-03 at 11:51 +0800, Peter Hung wrote:

+   for (i = 0; i < F81534_NUM_PORT; ++i)
+   atomic_set(&serial_priv->port_active[i], 0);


Should be ATOMIC_INIT()



ATOMIC_INIT() seems to be used only for variable initializer, It cant be
used for dynamic allocation. Should I change it to a normal boolean
flag protecting with spin_lock ?


No, if it doesn't work, use the current code.


OK, I'll use current code.


+static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr,


Is the point of passing a pointer to msr locking?


+   bool is_port_open)


This function is used only with URB callback function. The *msr is
reported by H/W with newest MSR. The USB-Serial generic system will
re-submit read URB when callback complete. So this function should
run once on the same time.


Yes, so why don't you pass an u8 as opposed to a pointer to an u8?


I'll re-write it from u8* to u8.


+static int f81534_tiocmget(struct tty_struct *tty)
+{
+   struct usb_serial_port *port = tty->driver_data;
+   struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+   unsigned long flags;
+   int r;
+   u8 msr, mcr;
+
+   /*
+* We'll avoid to direct read MSR register. The IC will read the MSR
+* changed and report it f81534_process_per_serial_block() by
+* F81534_TOKEN_MSR_CHANGE.
+*
+* When this device in heavy loading (e.g., BurnInTest Loopback Test)
+* The report of MSR register will delay received a bit. It's due to
+* MSR interrupt is lowest priority in 16550A. So we decide to sleep
+* a little time to pass the test.
+*/
+   if (schedule_timeout_interruptible(
+   msecs_to_jiffies(F81534_DELAY_READ_MSR))) {
+   dev_info(&port->dev, "%s: breaked !!\n", __func__);
+   }


Is the delay necessary or isn't it?
If it is necessary you should do something about the signal.



We add this delay due to stress test (Loop-back & 921600bps with
BurnInTest). It'll receive MSR with some delay when connecting with
DTR-DSR & RTS/CTS, but the delay smaller than 10ms. So we decided to
delay some time to pass the test.


OK, but how do you guarantee the delay you need if you get a signal,
which would abort the delay?



Hmm, you are right. It seems to replace *_interruptible to
*_killable and return -EINTR to guarantee not abort by normal
signal.


Thanks for your advices
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver

2015-11-04 Thread Peter Hung

Hi

Andy Shevchenko 於 2015/11/3 下午 05:45 寫道:

On Tue, Nov 3, 2015 at 5:51 AM, Peter Hung  wrote:

+ *Please reference https://bitbucket.org/hpeter/fintek-general/src/
+ *with f81534/tools to get set_gpio.c & set_mode.c. Please use it
+ *carefully.


Would it be good to have this under Documentation ?


I had some documents in source code. The link is the demo program to
implement switch UART/PIN funcion. I'll try to add for document with the
repository.


+static void f81534_dtr_rts(struct usb_serial_port *port, int on);
+
+static int f81534_set_port_mode(struct usb_serial_port *port,
+   enum uart_mode eMode);
+
+static int f81534_save_configure_data(struct usb_serial_port *port);
+
+static int f81534_switch_gpio_mode(struct usb_serial_port *port, u8 mode);
+
+static void f81534_wakeup_all_port(struct usb_serial *serial);
+
+static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr,
+   bool is_port_open);
+
+static int f81534_prepare_write_buffer(struct usb_serial_port *port,
+   void *dest, size_t size);
+
+static int f81534_submit_writer(struct usb_serial_port *port, gfp_t mem_flags);


Would it be possible to reshuffle code to reduce amount of forward declarations?



I'll try to reduce it.




+   if ((size <= F81534_MAX_DATA_BLOCK) &&
+   (read_size == (count + 1))) {


No need to have internal parens.



In my opinion, It makes more readable. Should I remove it?



+   if (baudrate <= 115200) {
+   value = 0x01;   /* 1.846m fixed */
+   divisor = f81534_calc_baud_divisor(baudrate, 115200, NULL);
+   port_priv->current_baud_base = 115200;
+   } else {
+   for (count = 0; count < ARRAY_SIZE(baudrate_table) ; ++count) {
+   baud_base = baudrate_table[count];
+   divisor = f81534_calc_baud_divisor(baudrate, baud_base,
+   &rem);
+   if (!rem) {
+   dev_dbg(&port->dev, "%s: found clockbase %d\n",
+   __func__,
+   baudrate_table[count]);
+   value = clock_table[count];
+   port_priv->current_baud_base = baud_base;
+   break;
+   }
+   }


Can you calculate baud rates more precisely? Any link to datasheet
where it's described?



I'll try to comment it within source code.


+static int f81534_ioctl_get_rs485(struct usb_serial_port *port,
+   struct serial_rs485 __user *arg)
+{
+   int status;
+   struct serial_rs485 data;
+   struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+   struct f81534_serial_private *serial_priv =
+   usb_get_serial_data(port->serial);


One line?



It's over 80 character with a tab, It cant be one line.

I'll fix other issue that you mention.

Thanks for your advices.
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver

2015-11-04 Thread Peter Hung

Hi

Oliver Neukum 於 2015/11/3 下午 06:03 寫道:

On Tue, 2015-11-03 at 11:51 +0800, Peter Hung wrote:

+static int f81534_attach(struct usb_serial *serial)
+{
+   struct f81534_serial_private *serial_priv = NULL;
+   int status;
+   int i;
+   int offset;
+   uintptr_t setting_idx = (uintptr_t) usb_get_serial_data(serial);
+
+   serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
+   if (!serial_priv)
+   return -ENOMEM;
+
+   usb_set_serial_data(serial, serial_priv);
+   serial_priv->setting_idx = setting_idx;
+
+   for (i = 0; i < F81534_NUM_PORT; ++i) {
+   /* Disable all interrupt before submit URB */
+   status = f81534_setregister(serial->dev, i,
+   INTERRUPT_ENABLE_REGISTER, 0x00);
+   if (status) {
+   dev_err(&serial->dev->dev, "%s: IER disable failed\n",
+   __func__);
+   goto failed;
+   }
+   }
+
+   for (i = 0; i < F81534_NUM_PORT; ++i)
+   atomic_set(&serial_priv->port_active[i], 0);


Should be ATOMIC_INIT()



ATOMIC_INIT() seems to be used only for variable initializer, It cant be
used for dynamic allocation. Should I change it to a normal boolean
flag protecting with spin_lock ?



+static int f81534_port_remove(struct usb_serial_port *port)
+{
+   struct f81534_port_private *port_priv;
+
+   f81534_release_gpio(port);
+   port_priv = usb_get_serial_port_data(port);
+   kfree(port_priv);
+   return 0;
+}
+
+static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr,


Is the point of passing a pointer to msr locking?


+   bool is_port_open)


This function is used only with URB callback function. The *msr is
reported by H/W with newest MSR. The USB-Serial generic system will
re-submit read URB when callback complete. So this function should
run once on the same time.


+static int f81534_tiocmget(struct tty_struct *tty)
+{
+   struct usb_serial_port *port = tty->driver_data;
+   struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+   unsigned long flags;
+   int r;
+   u8 msr, mcr;
+
+   /*
+* We'll avoid to direct read MSR register. The IC will read the MSR
+* changed and report it f81534_process_per_serial_block() by
+* F81534_TOKEN_MSR_CHANGE.
+*
+* When this device in heavy loading (e.g., BurnInTest Loopback Test)
+* The report of MSR register will delay received a bit. It's due to
+* MSR interrupt is lowest priority in 16550A. So we decide to sleep
+* a little time to pass the test.
+*/
+   if (schedule_timeout_interruptible(
+   msecs_to_jiffies(F81534_DELAY_READ_MSR))) {
+   dev_info(&port->dev, "%s: breaked !!\n", __func__);
+   }


Is the delay necessary or isn't it?
If it is necessary you should do something about the signal.



We add this delay due to stress test (Loop-back & 921600bps with
BurnInTest). It'll receive MSR with some delay when connecting with
DTR-DSR & RTS/CTS, but the delay smaller than 10ms. So we decided to
delay some time to pass the test.


+static int f81534_prepare_write_buffer(struct usb_serial_port *port,
+   void *dest, size_t size)
+{
+   unsigned char *ptr = (unsigned char *) dest;
+   struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+   int port_num = port_priv->phy;
+   struct usb_serial *serial = port->serial;
+
+   WARN_ON(size != serial->port[0]->bulk_out_size);
+
+   if (size != F81534_WRITE_BUFFER_SIZE) {
+   WARN_ON(size != F81534_WRITE_BUFFER_SIZE);


What is the sense of this?



I'll remove the double-check section with next version patch.



+   ptr[F81534_RECEIVE_BLOCK_SIZE * 0] = 0;
+   ptr[F81534_RECEIVE_BLOCK_SIZE * 1] = 1;
+   ptr[F81534_RECEIVE_BLOCK_SIZE * 2] = 2;
+   ptr[F81534_RECEIVE_BLOCK_SIZE * 3] = 3;


Either these ...


+   ptr[F81534_RECEIVE_BLOCK_SIZE * port_num + 0] = port_num;


.. or that is redundant



I'll remove it too.

Thanks for your advice.
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver

2015-11-02 Thread Peter Hung
This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

Features:
1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
2. Support Baudrate from B50 to B150 (excluding B100).
3. The RTS signal can be transformed their behavior with
   configuration by ioctl TIOCGRS485/TIOCSRS485

   If the driver setting with SER_RS485_ENABLED, the RTS signal will
   high with not in TX and low with in TX.

   If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
   the RTS signal will low with not in TX and high with in TX.

4. The 4x3 output-only open-drain pins for F81532/534 is designed for
   control outer devices (with our EVB for examples, the 4 sets of pins
   are designed to control transceiver mode). So it implements as
   gpiolib interface with output-only function.
5. It'll save the configuration in internal storage when uart/pins mode
   changed.

   Please reference https://bitbucket.org/hpeter/fintek-general/src/
   with f81534/tools to get set_gpio.c & set_mode.c to change F81532/534
   setting. Please use it carefully.

Signed-off-by: Peter Hung 
---
Changelog:
v6
1. Re-implement the write()/resume() function. Due to this device cant be
   suitable with generic write(), we'll do the submit write URB when
   write()/received tx empty/set_termios()/resume()
2. Logic/Phy Port mapping rewrite in f81534_port_probe() &
   f81534_phy_to_logic_port().
3. Introduced "Port Hide" function. Some customer use F81532 reference
   design for HW layout, but really use F81534 IC. We'll check
   F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do
   port hide with port not used. It can be avoid end-user to use not
   layouted port.
4. The 4x3 output-only open-drain pins for F81532/534 is designed for
   control outer devices (with our EVB for examples, the 4 sets of pins
   are designed to control transceiver mode). So we decide to implement
   with gpiolib interface.
  
v5
1. Change the configure data address F81534_CUSTOM_ADDRESS_START
   from 0x4000 to 0x2f00 (for MP F/W ver:AA66)
2. Change f81534_port_disable/enable() from H/W mode to S/W mode
   It'll skip all rx data when port is not opened.
3. Some function modifier add with static (Thanks for Paul Bolle)
4. It's will direct return when count=0 in f81534_write() to
   reduce spin_lock usage.

v4
1. clearify f81534_process_read_urb() with
   f81534_process_per_serial_block(). (referenced from mxuport.c)
2. We limited f81534_write() max tx kfifo with 124Bytes.
   Original subsystem is designed for auto tranmiting fifo data
   if available. But we must wait for tx_empty for next tx data
   (H/W design).

   With this kfifo size limit, we can use generic subsystem api with
   f81534_write(). When usb_serial_generic_write_start() called after
   first write URB complete, the fifo will no data. The generic
   subsystem of write will go to idle state. Until we received
   TX_EMPTY and release write spinlock, the fifo will fill max
   124Bytes by following f81534_write().

v3
1. Migrate read, write and some routine from custom code to usbserial
   subsystem callback function.
2. Use more defines to replece magic numbers to make it meaningful
3. Make more comments as document in source code.

v2
1. v1 version submit to staging tree, but Greg KH advised me to
   cleanup source code & re-submit it to correct subsystem
2. Remove all custom ioctl commands

 drivers/usb/serial/Kconfig  |   10 +
 drivers/usb/serial/Makefile |1 +
 drivers/usb/serial/f81534.c | 2991 +++
 3 files changed, 3002 insertions(+)
 create mode 100644 drivers/usb/serial/f81534.c

diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 56ecb8b..0642864 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -255,6 +255,16 @@ config USB_SERIAL_F81232
  To compile this driver as a module, choose M here: the
  module will be called f81232.
 
+config USB_SERIAL_F8153X
+   tristate "USB Fintek F81532/534 Multi-Ports Serial Driver"
+   help
+ Say Y here if you want to use the Fintek F81532/534 Multi-Ports
+ usb to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called f81534.
+
+
 config USB_SERIAL_GARMIN
tristate "USB Garmin GPS driver"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 349d9df..9e43b7b 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)   += io_ti.o
 obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
 obj-$(CONFIG_USB_SERIAL_F81

Re: [PATCH V5 1/1] usb:serial add Fintek F81532/534 driver

2015-10-21 Thread Peter Hung

Hi Johan,

Johan Hovold 於 2015/9/14 下午 09:33 寫道:

On Tue, Jul 21, 2015 at 09:58:19AM +0800, Peter Hung wrote:



   4. RS422 Mode
  1. The RTS mode is dont care.
  2. Set M2/M1/M0 as 0/0/0


I don't think all gpios should be exported for these ports if they have
special functions that the driver could control transparently (e.g. for
SER_RS485_RTS_ON_SEND).


Surely, we can hide some setting with definitely setting like
RS232/RS485, but the settings is only apply to our evaluation board.

Some customers will use our F81532/534 with other brand transceiver IC.
The pins setting maybe changed, so we decided to separate UART & pins
settings and let the 3 output pins controllable for customer.

Could I preserve currently UART & pins setting mode ?



+   current_mode &= BIT(gpio_num);
+
+   mutex_unlock(&serial_priv->change_mode_mutex);
+   f81534_wakeup_all_port(port->serial);
+
+   return !!current_mode;
+}


Your gpio implementation looks wrong, but let's get back to that after
you explain how these pins are used.

If they are not really general purpose pins, then this isn't the right
interface.


The 4x3 pins is output-only mode to control transceiver, so I'm only
implement the output functions and let all input functions failed.

Could you give some advices to me if the gpiolib interface cant be
used ?

Sorry for late reply, I'm almost ready to submit v6 when clarify some
questions.

Thanks,
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V5 1/1] usb:serial add Fintek F81532/534 driver

2015-09-17 Thread Peter Hung
Johan Hovold 於 2015/9/14 下午 09:33 寫道:
> On Tue, Jul 21, 2015 at 09:58:19AM +0800, Peter Hung wrote:
>> This driver is for Fintek F81532/F81534 USB to Serial Ports IC.
>>
> So as I mentioned above, always accept data if there's room in the fifo.
> Then kick of a write urb, if TX_EMPTY is set for any of the ports and
> fill the urb based on those flags as well.
> 

I'll try to improve it with V6, but it'll need more time to do
modification & verification. So V6 will release lately.

Thank you for your advice.

-- 
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V5 1/1] usb:serial add Fintek F81532/534 driver

2015-07-20 Thread Peter Hung
This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

Features:
1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
2. Support Baudrate from B50 to B150 (excluding B100).
3. The RTS signal can be transformed their behavior with
   configuration by default ioctl TIOCGRS485/TIOCSRS485
   (for RS232/RS485/RS422 with transceiver)

   If the driver setting with SER_RS485_ENABLED, the RTS signal will
   high with not in TX and low with in TX.

   If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
   the RTS signal will low with not in TX and high with in TX.

4. There are 4x3 output-only ic pins to control transceiver mode.
   It's can be controlled via gpiolib. We could found the gpio
   number from /sys/class/tty/ttyUSB[x]/device/gpiochap[yyy] where
   x is F81532/534 serial port and yyy is gpiochip number.

   After we found chip number, we can export 3 gpios(M2/M1/M0) per
   serial port by
  echo yyy > /sys/class/gpio/export
  echo yyy+1 > /sys/class/gpio/export
  echo yyy+2 > /sys/class/gpio/export

   then we can control it with
  echo [M0 value] > /sys/class/gpio/gpio[yyy]/value
  echo [M1 value] > /sys/class/gpio/gpio[yyy+1]/value
  echo [M2 value] > /sys/class/gpio/gpio[yyy+2]/value
   which M0/M1/M2 as your desired value, value is only 0 or 1.

   When configure complete, It's a must to free all gpio by
  echo yyy > /sys/class/gpio/unexport
  echo yyy+1 > /sys/class/gpio/unexport
  echo yyy+2 > /sys/class/gpio/unexport

   The driver will "save" gpio configure after we release
   all gpio of a serial port.

   For examples to change mode & gpio with F81532/534
   Evalaution Board.

   F81532 EVB
  port0: F81437 (RS232 only)
  port1: F81439 (RS232/RS485/RS422 ... etc.)
   F81534 EVB
  port0/1: F81437 (RS232 only)
  port2/3: F81439 (RS232/RS485/RS422 ... etc.)

  1. RS232 Mode (Default IC Mode)
 1. Set struct serial_rs485 flags "without" SER_RS485_ENABLED
(control F81532/534 RTS control)
 2. Set M2/M1/M0 as 0/0/1
(control F81532/534 output pin to control transceiver mode)

  2. RS485 Mode (RTS Low when TX Mode)
 1. Set struct serial_rs485 flags with SER_RS485_ENABLED
 2. Set M2/M1/M0 as 0/1/0

  3. RS485 Mode (RTS High when TX Mode)
 1. Set struct serial_rs485 flags with SER_RS485_ENABLED and
SER_RS485_RTS_ON_SEND
 2. Set M2/M1/M0 as 0/1/1

  4. RS422 Mode
 1. The RTS mode is dont care.
 2. Set M2/M1/M0 as 0/0/0

   Please reference https://bitbucket.org/hpeter/fintek-general/src/
   with f81534/tools to get set_gpio.c & set_mode.c. Please use it
   carefully.

Changelog
v5
1. Change the configure data address F81534_CUSTOM_ADDRESS_START
   from 0x4000 to 0x2f00 (for MP F/W ver:AA66)
2. Change f81534_port_disable/enable() from H/W mode to S/W mode
   It'll skip all rx data when port is not opened.
3. Some function modifier add with static (Thanks for Paul Bolle)
4. It's will direct return when count=0 in f81534_write() to
   reduce spin_lock usage.

v4
1. clearify f81534_process_read_urb() with
   f81534_process_per_serial_block(). (referenced from mxuport.c)
2. We limited f81534_write() max tx kfifo with 124Bytes.
   Original subsystem is designed for auto tranmiting fifo data
   if available. But we must wait for tx_empty for next tx data
   (H/W design).

   With this kfifo size limit, we can use generic subsystem api with
   f81534_write(). When usb_serial_generic_write_start() called after
   first write URB complete, the fifo will no data. The generic
   subsystem of write will go to idle state. Until we received
   TX_EMPTY and release write spinlock, the fifo will fill max
   124Bytes by following f81534_write().

v3
1. Migrate read, write and some routine from custom code to usbserial
   subsystem callback function.
2. Use more defines to replece magic numbers to make it meaningful
3. Make more comments as document in source code.

v2
1. v1 version submit to staging tree, but Greg KH advised me to
   cleanup source code & re-submit it to correct subsystem
2. Remove all custom ioctl commands

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/Kconfig  |   10 +
 drivers/usb/serial/Makefile |1 +
 drivers/usb/serial/f81534.c | 3279 +++
 3 files changed, 3290 insertions(+)
 create mode 100644 drivers/usb/serial/f81534.c

diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 56ecb8b..0642864 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -255,6 +255,16 @@ config USB_SERIAL_F81232
  To compile this driver as a module, choose M here: the
  module will be called f81232.
 
+config USB_SERIAL_F81

Re: [PATCH V4 1/1] usb:serial:f81534 add F81532/534 driver

2015-07-15 Thread Peter Hung

Hi Paul & Johan

Paul Bolle 於 2015/7/15 下午 04:36 寫道:

Just a few nits, I'm afraid.

+int f81534_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+   [...]
+}


static?


Thanks Paul for point this out.

And sorry for Johan. It's seems to make a new patch V5. I'll merge
some minor fix with newer patch.
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V4 1/1] usb:serial:f81534 add F81532/534 driver

2015-07-13 Thread Peter Hung
This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

Features:
1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
2. Support Baudrate from B50 to B150 (excluding B100).
3. The RTS signal can be transformed their behavior with
   configuration by default ioctl TIOCGRS485/TIOCSRS485
   (for RS232/RS485/RS422 with transceiver)

   If the driver setting with SER_RS485_ENABLED, the RTS signal will
   high with not in TX and low with in TX.

   If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
   the RTS signal will low with not in TX and high with in TX.

4. There are 4x3 output-only ic pins to control transceiver mode.
   It's can be controlled via gpiolib. We could found the gpio
   number from /sys/class/tty/ttyUSB[x]/device/gpiochap[yyy] where
   x is F81532/534 serial port and yyy is gpiochip number.

   After we found chip number, we can export 3 gpios(M2/M1/M0) per
   serial port by
  echo yyy > /sys/class/gpio/export
  echo yyy+1 > /sys/class/gpio/export
  echo yyy+2 > /sys/class/gpio/export

   then we can control it with
  echo [M0 value] > /sys/class/gpio/gpio[yyy]/value
  echo [M1 value] > /sys/class/gpio/gpio[yyy+1]/value
  echo [M2 value] > /sys/class/gpio/gpio[yyy+2]/value
   which M0/M1/M2 as your desired value, value is only 0 or 1.

   When configure complete, It's a must to free all gpio by
  echo yyy > /sys/class/gpio/unexport
  echo yyy+1 > /sys/class/gpio/unexport
  echo yyy+2 > /sys/class/gpio/unexport

   The driver will "save" gpio configure after we release
   all gpio of a serial port.

   For examples to change mode & gpio with F81532/534
   Evalaution Board.

   F81532 EVB
  port0: F81437 (RS232 only)
  port1: F81439 (RS232/RS485/RS422 ... etc.)
   F81534 EVB
  port0/1: F81437 (RS232 only)
  port2/3: F81439 (RS232/RS485/RS422 ... etc.)

  1. RS232 Mode (Default IC Mode)
 1. Set struct serial_rs485 flags "without" SER_RS485_ENABLED
(control F81532/534 RTS control)
 2. Set M2/M1/M0 as 0/0/1
(control F81532/534 output pin to control transceiver mode)

  2. RS485 Mode (RTS Low when TX Mode)
 1. Set struct serial_rs485 flags with SER_RS485_ENABLED
 2. Set M2/M1/M0 as 0/1/0

  3. RS485 Mode (RTS High when TX Mode)
 1. Set struct serial_rs485 flags with SER_RS485_ENABLED and
SER_RS485_RTS_ON_SEND
 2. Set M2/M1/M0 as 0/1/1

  4. RS422 Mode
 1. The RTS mode is dont care.
 2. Set M2/M1/M0 as 0/0/0

   Please reference https://bitbucket.org/hpeter/fintek-general/src/
   with f81534/tools to get set_gpio.c & set_mode.c. Please use it
   carefully.

Changelog
v4
1. clearify f81534_process_read_urb() with
   f81534_process_per_serial_block(). (referenced from mxuport.c)
2. We limited f81534_write() max tx kfifo with 124Bytes.
   Original subsystem is designed for auto tranmiting fifo data
   if available. But we must wait for tx_empty for next tx data
   (H/W design).

   With this kfifo size limit, we can use generic subsystem api with
   f81534_write(). When usb_serial_generic_write_start() called after
   first write URB complete, the fifo will no data. The generic
   subsystem of write will go to idle state. Until we received TX_EMPTY
   and release write spinlock, the fifo will fill max 124Bytes by
   following f81534_write().

v3
1. Migrate read, write and some routine from custom code to usbserial
   subsystem callback function.
2. Use more defines to replece magic numbers to make it meaningful
3. Make more comments as document in source code.

v2
1. v1 version submit to staging tree, but Greg KH advised me to
   cleanup source code & re-submit it to correct subsystem
2. Remove all custom ioctl commands

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/Kconfig  |   10 +
 drivers/usb/serial/Makefile |1 +
 drivers/usb/serial/f81534.c | 3315 +++
 3 files changed, 3326 insertions(+)
 create mode 100644 drivers/usb/serial/f81534.c

diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 56ecb8b..0642864 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -255,6 +255,16 @@ config USB_SERIAL_F81232
  To compile this driver as a module, choose M here: the
  module will be called f81232.
 
+config USB_SERIAL_F8153X
+   tristate "USB Fintek F81532/534 Multi-Ports Serial Driver"
+   help
+ Say Y here if you want to use the Fintek F81532/534 Multi-Ports
+ usb to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called f81534.
+
+
 config USB_SERIAL_GARMIN
tristate "USB Garmin GPS driver"
help
diff --git a/drivers/usb/serial/

Re: [PATCH V3 1/1] usb:serial:f81534 add F81532/534 driver

2015-07-10 Thread Peter Hung
Hi Johan,

Peter Hung 於 2015/7/9 上午 11:15 寫道:
> This driver is for Fintek F81532/F81534 USB to Serial Ports IC.
> 

Please pending for the driver, I found a problem with
prepare_write_buffer(). The driver submit write block size
!= real tx send size. It's will ok on transmitting small mount data,
but it's will fail on transmitting large mount data.

I'll fix for this problem and re-send patch.
Sorry for found bug so lately.

-- 
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V3 1/1] usb:serial:f81534 add F81532/534 driver

2015-07-08 Thread Peter Hung
This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

Features:
1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
2. Support Baudrate from B50 to B150 (excluding B100).
3. The RTS signal can be transformed their behavior with
   configuration by default ioctl TIOCGRS485/TIOCSRS485
   (for RS232/RS485/RS422 with transceiver)

   If the driver setting with SER_RS485_ENABLED, the RTS signal will
   high with not in TX and low with in TX.

   If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
   the RTS signal will low with not in TX and high with in TX.

4. There are 4x3 output-only ic pins to control transceiver mode.
   It's can be controlled via gpiolib. We could found the gpio
   number from /sys/class/tty/ttyUSB[x]/device/gpiochap[yyy] where
   x is F81532/534 serial port and yyy is gpiochip number.

   After we found chip number, we can export 3 gpios(M2/M1/M0) per
   serial port by
  echo yyy > /sys/class/gpio/export
  echo yyy+1 > /sys/class/gpio/export
  echo yyy+2 > /sys/class/gpio/export

   then we can control it with
  echo [M0 value] > /sys/class/gpio/gpio[yyy]/value
  echo [M1 value] > /sys/class/gpio/gpio[yyy+1]/value
  echo [M2 value] > /sys/class/gpio/gpio[yyy+2]/value
   which M0/M1/M2 as your desired value, value is only 0 or 1.

   When configure complete, It's a must to free all gpio by
  echo yyy > /sys/class/gpio/unexport
  echo yyy+1 > /sys/class/gpio/unexport
  echo yyy+2 > /sys/class/gpio/unexport

   The driver will "save" gpio configure after we release
   all gpio of a serial port.

   For examples to change mode & gpio with F81532/534
   Evalaution Board.

   F81532 EVB
  port0: F81437 (RS232 only)
  port1: F81439 (RS232/RS485/RS422 ... etc.)
   F81534 EVB
  port0/1: F81437 (RS232 only)
  port2/3: F81439 (RS232/RS485/RS422 ... etc.)

  1. RS232 Mode (Default IC Mode)
 1. Set struct serial_rs485 flags "without" SER_RS485_ENABLED
(control F81532/534 RTS control)
 2. Set M2/M1/M0 as 0/0/1
(control F81532/534 output pin to control transceiver mode)

  2. RS485 Mode (RTS Low when TX Mode)
 1. Set struct serial_rs485 flags with SER_RS485_ENABLED
 2. Set M2/M1/M0 as 0/1/0

  3. RS485 Mode (RTS High when TX Mode)
 1. Set struct serial_rs485 flags with SER_RS485_ENABLED and
SER_RS485_RTS_ON_SEND
 2. Set M2/M1/M0 as 0/1/1

  4. RS422 Mode
 1. The RTS mode is dont care.
 2. Set M2/M1/M0 as 0/0/0

   Please reference https://bitbucket.org/hpeter/fintek-general/src/
   with f81534/tools to get set_gpio.c & set_mode.c. Please use it
   carefully.

Changelog
v3
1. Migrate read, write and some routine from custom code to usbserial
   subsystem callback function.
2. Use more defines to replece magic numbers to make it meaningful
3. Make more comments as document in source code.

v2
1. v1 version submit to staging tree, but Greg KH advised me to
   cleanup source code & re-submit it to correct subsystem
2. Remove all custom ioctl commands

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/Kconfig  |   10 +
 drivers/usb/serial/Makefile |1 +
 drivers/usb/serial/f81534.c | 3316 +++
 3 files changed, 3327 insertions(+)
 create mode 100644 drivers/usb/serial/f81534.c

diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 56ecb8b..0642864 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -255,6 +255,16 @@ config USB_SERIAL_F81232
  To compile this driver as a module, choose M here: the
  module will be called f81232.
 
+config USB_SERIAL_F8153X
+   tristate "USB Fintek F81532/534 Multi-Ports Serial Driver"
+   help
+ Say Y here if you want to use the Fintek F81532/534 Multi-Ports
+ usb to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called f81534.
+
+
 config USB_SERIAL_GARMIN
tristate "USB Garmin GPS driver"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 349d9df..9e43b7b 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)   += io_ti.o
 obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
 obj-$(CONFIG_USB_SERIAL_F81232)+= f81232.o
+obj-$(CONFIG_USB_SERIAL_F8153X)+= f81534.o
 obj-$(CONFIG_USB_SERIAL_FTDI_SIO)  += ftdi_sio.o
 obj-$(CONFIG_USB_SERIAL_GARMIN)+= garmin_gps.o
 obj-$(CONFIG_USB_SERIAL_IPAQ)  += ipaq.o
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.

Re: [PATCH V2 1/1] usb:serial:f81534 Add F81532/534 Driver

2015-06-25 Thread Peter Hung

Hi Johan,

Johan Hovold 於 2015/6/25 下午 04:06 寫道:

  - As Greg already mentioned, you need to implement gpio support using
gpiolib, not a custom sysfs interface

I don't have time to look closer at the architectural bits until next
week I'm afraid, but perhaps you could start with the above.


Thanks for your advices, I'll try to improve it again.
But I had something need to clarify.

1. The sysfs interface of the driver provide "limited output pin"
   control. only support output 0/1, not support input mode.
   Should I implement it as gpiolib?

2. If it still recommends to implement with gpiolib, Could I implement
   it and preserve the sysfs interface for legacy?

--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V2 1/1] usb:serial:f81534 Add F81532/534 Driver

2015-06-24 Thread Peter Hung
Hello Johan,

Peter Hung 於 2015/6/15 上午 09:54 寫道:
> This driver is for Fintek F81532/F81534 USB to Serial Ports IC.
> 
> Features:
> 1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
> 2. Support Baudrate from B50 to B150 (excluding B100).
> 3. The RTS signal can be transformed their behavior with configuration
> for transceiver (for RS232/RS485/RS422) (/sys/class/ttyUSBx/uart_mode)
> 4. There are 4x3 output-only GPIOs to control transceiver mode. It's
> can be controlled via sysfs (/sys/class/ttyUSBx/gpio)
> 

Do you receive my patch?
Are there anything should I do to improve it ?

-- 
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V2 1/1] usb:serial:f81534 Add F81532/534 Driver

2015-06-14 Thread Peter Hung
This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

Features:
1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
2. Support Baudrate from B50 to B150 (excluding B100).
3. The RTS signal can be transformed their behavior with configuration
   for transceiver (for RS232/RS485/RS422) (/sys/class/ttyUSBx/uart_mode)
4. There are 4x3 output-only GPIOs to control transceiver mode. It's
   can be controlled via sysfs (/sys/class/ttyUSBx/gpio)

Changelog from v1:
1. v1 version submit to staging tree, but Greg KH advised me to cleanup
   source code & re-submit it to correct subsystem
2. Remove all custom ioctl commands

If had any question, Please send email to
hpeter+linux_ker...@gmail.com
peter_h...@fintek.com.tw

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/Kconfig  |   10 +
 drivers/usb/serial/Makefile |1 +
 drivers/usb/serial/f81534.c | 3162 +++
 3 files changed, 3173 insertions(+)
 create mode 100644 drivers/usb/serial/f81534.c

diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index b7cf198..4bf3011 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -255,6 +255,16 @@ config USB_SERIAL_F81232
  To compile this driver as a module, choose M here: the
  module will be called f81232.
 
+config USB_SERIAL_F8153X
+   tristate "USB Fintek F81532/534 Multi-Ports Serial Driver"
+   help
+ Say Y here if you want to use the Fintek F81532/534 Multi-Ports
+ usb to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called f81534.
+
+
 config USB_SERIAL_GARMIN
tristate "USB Garmin GPS driver"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 349d9df..9e43b7b 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)   += io_ti.o
 obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
 obj-$(CONFIG_USB_SERIAL_F81232)+= f81232.o
+obj-$(CONFIG_USB_SERIAL_F8153X)+= f81534.o
 obj-$(CONFIG_USB_SERIAL_FTDI_SIO)  += ftdi_sio.o
 obj-$(CONFIG_USB_SERIAL_GARMIN)+= garmin_gps.o
 obj-$(CONFIG_USB_SERIAL_IPAQ)  += ipaq.o
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
new file mode 100644
index 000..8c817ee
--- /dev/null
+++ b/drivers/usb/serial/f81534.c
@@ -0,0 +1,3162 @@
+/*
+ * F81532/F81534 USB to Serial Ports Bridge
+ *
+ * F81532 => 2 Serial Ports
+ * F81534 => 4 Serial Ports
+ *
+ * Copyright (C) 2014 Tom Tsai (tom_t...@fintek.com.tw)
+ *
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Serial Port register Address */
+#define SERIAL_BASE_ADDRESS0x1200
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
+#define TRANSMIT_HOLDING_REGISTER  (0x00 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_IDENT_REGISTER   (0x02 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
+#define LINE_STATUS_REGISTER   (0x05 + SERIAL_BASE_ADDRESS)
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
+#define CLK_SEL_REGISTER   (0x08 + SERIAL_BASE_ADDRESS)
+#define CONFIG1_REGISTER   (0x09 + SERIAL_BASE_ADDRESS)
+#define SADDRESS_REGISTER  (0x0a + SERIAL_BASE_ADDRESS)
+#define SADEN_REGISTER (0x0b + SERIAL_BASE_ADDRESS)
+#define DIVISOR_LATCH_LSB  (0x00 + SERIAL_BASE_ADDRESS)
+#define DIVISOR_LATCH_MSB  (0x01 + SERIAL_BASE_ADDRESS)
+#define SCRATCH_PAD_REGISTER   (0x07 + SERIAL_BASE_ADDRESS)
+
+#define F81534_RESERVE_ADDRESS_START   0x3000
+#define F81534_RESERVE_SIZE8
+
+#define F81534_CUSTOM_ADDRESS_START0x4000
+#define F81534_CUSTOM_TOTAL_SIZE   0x1000
+
+#define F81534_CUSTOM_DATA_SIZE0x10
+#define F81534_CUSTOM_MAX_IDX \
+   (F81534_CUSTOM_TOTAL_SIZE/F81534_CUSTOM_DATA_SIZE)
+#define F81534_CUSTOM_NO_CUSTOM_DATA   (-1)
+
+#define F81534_MAX_DATA_BLOCK  64
+#define F81534_BUSY_STATUS 0x03
+#define F81534_MAX_BUS_RETRY   2000
+
+/* default urb timeout for usb operations */
+#define F81534_USB_MAX_RETRY   5
+#define F81534_USB_TIMEOUT 1000
+#define F81534_CONTROL_BYTE0x1B
+#define F81534_SET_GET_REGISTER0xA0
+
+#define F81534_NUM_PORT4
+#defi

Re: [PATCH 1/1] staging:f81534 Add F81532/534 Driver

2015-06-11 Thread Peter Hung

Greg KH 於 2015/6/12 下午 12:33 寫道:

Why not just do the work now to clean up the file and get it merged
"properly"?  Why put this in staging at all?



I'll clear up the file and resend it to usb-serial subsystem mail list.
Thanks for your advices.

--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/1] staging:f81534 Add F81532/534 Driver

2015-06-11 Thread Peter Hung
This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

Features:
1.  F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
2.  Support Baudrate from B50 to B150 (excluding B100).
3.  The RTS signal can be transformed their behavior with 
configuration
for transceiver (for RS232/RS485/RS422)
4.  There are 4x3 GPIOs to control transceiver. It's can be 
controlled
with sysfs

If had any question, Please send email to
hpeter+linux_ker...@gmail.com
peter_h...@fintek.com.tw

Patches Welcome :D

Signed-off-by: Peter Hung 
---
 drivers/staging/Kconfig |2 +
 drivers/staging/Makefile|1 +
 drivers/staging/f81534/Kconfig  |   10 +
 drivers/staging/f81534/Makefile |1 +
 drivers/staging/f81534/Readme   |9 +
 drivers/staging/f81534/TODO |   12 +
 drivers/staging/f81534/f81534.c | 3335 +++
 7 files changed, 3370 insertions(+)
 create mode 100644 drivers/staging/f81534/Kconfig
 create mode 100644 drivers/staging/f81534/Makefile
 create mode 100644 drivers/staging/f81534/Readme
 create mode 100644 drivers/staging/f81534/TODO
 create mode 100644 drivers/staging/f81534/f81534.c

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 7f6cae5..b7c0bd0 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -112,4 +112,6 @@ source "drivers/staging/fsl-mc/Kconfig"
 
 source "drivers/staging/wilc1000/Kconfig"
 
+source "drivers/staging/f81534/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 347f647..9d17cb8 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -48,3 +48,4 @@ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
 obj-$(CONFIG_FB_TFT)   += fbtft/
 obj-$(CONFIG_FSL_MC_BUS)   += fsl-mc/
 obj-$(CONFIG_WILC1000) += wilc1000/
+obj-$(CONFIG_USB_SERIAL_F8153X)+= f81534/
diff --git a/drivers/staging/f81534/Kconfig b/drivers/staging/f81534/Kconfig
new file mode 100644
index 000..41bf55c
--- /dev/null
+++ b/drivers/staging/f81534/Kconfig
@@ -0,0 +1,10 @@
+#
+# Xilinx Clocking Wizard Driver
+#
+
+config USB_SERIAL_F8153X
+   tristate "F81532/534 USB to Serial Ports Driver"
+   depends on USB_SERIAL
+   default m
+   ---help---
+ Support for Fintek F81532/534 USB to Serial Ports board
diff --git a/drivers/staging/f81534/Makefile b/drivers/staging/f81534/Makefile
new file mode 100644
index 000..d73178d
--- /dev/null
+++ b/drivers/staging/f81534/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_SERIAL_F8153X)+= f81534.o
diff --git a/drivers/staging/f81534/Readme b/drivers/staging/f81534/Readme
new file mode 100644
index 000..00b72b0
--- /dev/null
+++ b/drivers/staging/f81534/Readme
@@ -0,0 +1,9 @@
+This driver is for Fintek F81534/F81532
+
+Features:
+   1.  F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
+   2.  Support Baudrate from B50 to B150 (excluding B100).
+   3.  The RTS signal can be transformed their behavior with 
configuration
+   for transceiver (for RS232/RS485/RS422)
+   4.  There are 4x3 GPIOs to control transceiver. It's can be 
controlled with
+   sysfs
\ No newline at end of file
diff --git a/drivers/staging/f81534/TODO b/drivers/staging/f81534/TODO
new file mode 100644
index 000..422bdf2
--- /dev/null
+++ b/drivers/staging/f81534/TODO
@@ -0,0 +1,12 @@
+Current Progress
+   - Functional Test ok (BurninTest 921600bps 4Port / S4 / S5)
+
+TODO:
+   - Code review
+   - checkpatch.pl
+
+Welcome to send patch for F81532/534 If you found a problem.
+
+Patches to:
+   Greg Kroah-Hartman 
+   Peter Hong 
diff --git a/drivers/staging/f81534/f81534.c b/drivers/staging/f81534/f81534.c
new file mode 100644
index 000..f6f5c2b
--- /dev/null
+++ b/drivers/staging/f81534/f81534.c
@@ -0,0 +1,3335 @@
+/*
+ * F81532/F81534 USB to Serial Ports Bridge
+ *
+ * F81532 => 2 Serial Ports
+ * F81534 => 4 Serial Ports
+ *
+ * Copyright (C) 2014 Tom Tsai (tom_t...@fintek.com.tw)
+ *
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Serial Port register Address */
+#define SERIAL_BASE_ADDRESS0x1200
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
+#define TRANSMIT_HOLDING_REGISTER  (0x00 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_IDENT_REGISTER   (0x02 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
+#define MODEM_CONTROL_REGISTER (0x04 + SE

Re: [PATCH V9 02/10] USB: f81232: implement RX bulk-in EP

2015-03-31 Thread Peter Hung

Hello,

Thanks for your kindly support and code review.
It's my honor to work with you :D


Johan Hovold 於 2015/3/28 上午 12:17 寫道:


I'll apply the whole series now. Thanks again for fixing up this driver!

Johan



--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V9 02/10] USB: f81232: implement RX bulk-in EP

2015-03-17 Thread Peter Hung
The F81232 bulk-in is RX data + LSR channel, data format is
[LSR+Data][LSR+Data]. , We had implemented in f81232_process_read_urb().

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 73 +
 1 file changed, 40 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 669a2f2..6b83870b 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 
 static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1934, 0x0706) },
@@ -104,44 +105,50 @@ exit:
 static void f81232_process_read_urb(struct urb *urb)
 {
struct usb_serial_port *port = urb->context;
-   struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
-   char tty_flag = TTY_NORMAL;
-   unsigned long flags;
-   u8 line_status;
-   int i;
+   char tty_flag;
+   unsigned int i;
+   u8 lsr;
 
-   /* update line status */
-   spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->modem_status;
-   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
-   spin_unlock_irqrestore(&priv->lock, flags);
+   /* It's had 1-byte packet on open, the data is current LSR. but
+* in this situation, the byte useless for open.
+*/
 
-   if (!urb->actual_length)
+   if ((urb->actual_length < 2) || (urb->actual_length % 2))
return;
 
-   /* break takes precedence over parity, */
-   /* which takes precedence over framing errors */
-   if (line_status & UART_BREAK_ERROR)
-   tty_flag = TTY_BREAK;
-   else if (line_status & UART_PARITY_ERROR)
-   tty_flag = TTY_PARITY;
-   else if (line_status & UART_FRAME_ERROR)
-   tty_flag = TTY_FRAME;
-   dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
-
-   /* overrun is special, not associated with a char */
-   if (line_status & UART_OVERRUN_ERROR)
-   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
-   if (port->port.console && port->sysrq) {
-   for (i = 0; i < urb->actual_length; ++i)
-   if (!usb_serial_handle_sysrq_char(port, data[i]))
-   tty_insert_flip_char(&port->port, data[i],
-   tty_flag);
-   } else {
-   tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
-   urb->actual_length);
+   /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
+
+   for (i = 0; i < urb->actual_length; i += 2) {
+   tty_flag = TTY_NORMAL;
+   lsr = data[i];
+
+   if (lsr & UART_LSR_BRK_ERROR_BITS) {
+   if (lsr & UART_LSR_BI) {
+   tty_flag = TTY_BREAK;
+   port->icount.brk++;
+   usb_serial_handle_break(port);
+   } else if (lsr & UART_LSR_PE) {
+   tty_flag = TTY_PARITY;
+   port->icount.parity++;
+   } else if (lsr & UART_LSR_FE) {
+   tty_flag = TTY_FRAME;
+   port->icount.frame++;
+   }
+
+   if (lsr & UART_LSR_OE) {
+   port->icount.overrun++;
+   tty_insert_flip_char(&port->port, 0,
+   TTY_OVERRUN);
+   }
+   }
+
+   if (port->port.console && port->sysrq) {
+   if (usb_serial_handle_sysrq_char(port, data[i + 1]))
+   continue;
+   }
+
+   tty_insert_flip_char(&port->port, data[i + 1], tty_flag);
}
 
tty_flip_buffer_push(&port->port);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V9 01/10] USB: f81232: rename private struct member name

2015-03-17 Thread Peter Hung
Change private struct member name from line_status to modem_status.
It will store MSR for some functions used

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c5dc233..669a2f2 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,7 +47,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 struct f81232_private {
spinlock_t lock;
u8 line_control;
-   u8 line_status;
+   u8 modem_status;
 };
 
 static void f81232_update_line_status(struct usb_serial_port *port,
@@ -113,8 +113,8 @@ static void f81232_process_read_urb(struct urb *urb)
 
/* update line status */
spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->line_status;
-   priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+   line_status = priv->modem_status;
+   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
 
if (!urb->actual_length)
@@ -241,7 +241,7 @@ static void f81232_dtr_rts(struct usb_serial_port *port, 
int on)
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   if (priv->line_status & UART_DCD)
+   if (priv->modem_status & UART_DCD)
return 1;
return 0;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V9 03/10] USB: f81232: change lock mechanism

2015-03-17 Thread Peter Hung
The original driver lock with spin_lock_irqsave()/spin_unlock_irqrestore()
because of it's maybe used in interrupt context f81232_process_read_urb().

We had remove it from previous patch "implement RX bulk-in EP", so we can
change it from busying loop spin_lock to sleepable mutex_lock.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 6b83870b..61a6a1a 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -19,7 +19,7 @@
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -46,7 +46,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define UART_CTS   0x80
 
 struct f81232_private {
-   spinlock_t lock;
+   struct mutex lock;
u8 line_control;
u8 modem_status;
 };
@@ -231,17 +231,16 @@ static void f81232_close(struct usb_serial_port *port)
 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   unsigned long flags;
u8 control;
 
-   spin_lock_irqsave(&priv->lock, flags);
+   mutex_lock(&priv->lock);
/* Change DTR and RTS */
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);
+   mutex_unlock(&priv->lock);
set_control_lines(port->serial->dev, control);
 }
 
@@ -285,7 +284,7 @@ static int f81232_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;
 
-   spin_lock_init(&priv->lock);
+   mutex_init(&priv->lock);
 
usb_set_serial_port_data(port, priv);
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V9 04/10] USB: f81232: implement read IIR/MSR with endpoint

2015-03-17 Thread Peter Hung
The interrupt endpoint will report current IIR. If we got IIR with MSR changed
, We will do read MSR with interrupt_work worker to do f81232_read_msr()
function.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 126 +---
 1 file changed, 118 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 61a6a1a..1e1261f 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -31,6 +31,13 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* USB Control EP parameter */
+#define F81232_REGISTER_REQUEST0xa0
+#define F81232_GET_REGISTER0xc0
+
+#define SERIAL_BASE_ADDRESS0x0120
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
+
 #define CONTROL_DTR0x01
 #define CONTROL_RTS0x02
 
@@ -49,19 +56,112 @@ struct f81232_private {
struct mutex lock;
u8 line_control;
u8 modem_status;
+   struct work_struct interrupt_work;
+   struct usb_serial_port *port;
 };
 
+static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
+{
+   int status;
+   u8 *tmp;
+   struct usb_device *dev = port->serial->dev;
+
+   tmp = kmalloc(sizeof(*val), GFP_KERNEL);
+   if (!tmp)
+   return -ENOMEM;
+
+   status = usb_control_msg(dev,
+   usb_rcvctrlpipe(dev, 0),
+   F81232_REGISTER_REQUEST,
+   F81232_GET_REGISTER,
+   reg,
+   0,
+   tmp,
+   sizeof(*val),
+   USB_CTRL_GET_TIMEOUT);
+   if (status != sizeof(*val)) {
+   dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
+
+   if (status < 0)
+   status = usb_translate_errors(status);
+   else
+   status = -EIO;
+   } else {
+   status = 0;
+   *val = *tmp;
+   }
+
+   kfree(tmp);
+   return status;
+}
+
+static void f81232_read_msr(struct usb_serial_port *port)
+{
+   int status;
+   u8 current_msr;
+   struct tty_struct *tty;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   mutex_lock(&priv->lock);
+   status = f81232_get_register(port, MODEM_STATUS_REGISTER,
+   ¤t_msr);
+   if (status) {
+   dev_err(&port->dev, "%s fail, status: %d\n", __func__, status);
+   mutex_unlock(&priv->lock);
+   return;
+   }
+
+   if (!(current_msr & UART_MSR_ANY_DELTA)) {
+   mutex_unlock(&priv->lock);
+   return;
+   }
+
+   priv->modem_status = current_msr;
+
+   if (current_msr & UART_MSR_DCTS)
+   port->icount.cts++;
+   if (current_msr & UART_MSR_DDSR)
+   port->icount.dsr++;
+   if (current_msr & UART_MSR_TERI)
+   port->icount.rng++;
+   if (current_msr & UART_MSR_DDCD) {
+   port->icount.dcd++;
+   tty = tty_port_tty_get(&port->port);
+   if (tty) {
+   usb_serial_handle_dcd_change(port, tty,
+   current_msr & UART_MSR_DCD);
+
+   tty_kref_put(tty);
+   }
+   }
+
+   wake_up_interruptible(&port->port.delta_msr_wait);
+   mutex_unlock(&priv->lock);
+}
+
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
- unsigned int actual_length)
+ size_t actual_length)
 {
-   /*
-* FIXME: Update port->icount, and call
-*
-*  wake_up_interruptible(&port->port.delta_msr_wait);
-*
-*on MSR changes.
-*/
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (!actual_length)
+   return;
+
+   switch (data[0] & 0x07) {
+   case 0x00: /* msr change */
+   dev_dbg(&port->dev, "IIR: MSR Change: %02x\n", data[0]);
+   schedule_work(&priv->interrupt_work);
+   break;
+   case 0x02: /* tx-empty */
+   break;
+   case 0x04: /* rx data available */
+   break;
+   case 0x06: /* lsr change */
+   /* we can forget it. the LSR will read from bulk-in */
+   dev_dbg(&port->dev, "IIR: LSR Change: %02x\n", data[0]);
+   break;
+   }
 }
 
 static void f81232_r

[PATCH V9 00/10] usb: serial: F81232 V9 patches

2015-03-17 Thread Peter Hung
This series patch V9 is changed from V8 as following:

1. add comments for read URB 1byte LSR when port open.
2. change error handle flow of set_register()/get_register()

V8 (old change):
1. The V7 MSR strange delta value is checked with locking problem. We changed
   f81232_set_mctrl() & f81232_read_msr() lock mechanism, the old version is
   only locked with variable protection, new version will lock from start to
   end with these 2 function.   
2. f81232_set_baudrate() add error handling and no longer handle with baudrate
   B0, change to handle with f81232_set_termios()
3. When user set baudrate larger then 115200, we will change it with 115200
   and tty_encode_baud_rate() in f81232_set_termios().
4. V7 f81232_set_baudrate() divisor declared with type u8, it will make 
   baudrate set failed with smaller then B600 (115200/300=384 overflow :Q).
   We changed it with integer type for divisor larger then 256.
   
V7 (old change):

1. The buffer of usb_control_msg() in set_register()/get_register() are change
   from local variable to kmalloc(). (PATCH V7 02/11)
2. Change all set_register()/get_register() return value 0 is success, 
   otherwise are failed. ( return 0 of usb_control_msg() treat as -EIO, 
   PATCH V7 02/11)
3. tty_port_tty_get() called only when DCD has changed. (PATCH V7 05/11)  
4. remove likely()/unlikely() branch prediction.
5. Implement DTR/RTS control when baudrate B0. We drop DTR/RTS when B0, 
   otherwise enable it. (PATCH V7 08/11)
6. Change private struct line_control to modem_control with meanful. 
   (PATCH V7 06/11)
7. We confirmd MSR strange delta value is not locking-issue. The issue
   maybe reproduce with set MCR & get MSR before IIR notice with MSR changed.
   
V6 (old change):

1. transform all function not to use private data as parameter, using
   usb_serial_port instead.
2. process_read_urb() add process of Break/FrameError/ParityError/OE.
   (patch: 03/10)
3. fix calc_baud_divisor() will cause divide by zero with B0. (patch: 04/10)
4. Some init step we extract it from set_termios() to f81232_port_init()
   and run it when open port only. (patch: 04/10)
5. We'll force re-read msr in tiocmget() because the IIR with MSR change
   maybe delay received. (patch: 05/10)
6. fix MSR status bits changed but delta bits is 0 will cause read serial port
   malfunctional with update port status. (patch: 08/10)
7. Add MSR change statistic when MSR has been read. (patch: 09/10)   
8. clarify a lot of code about Johan suggested.

Peter Hung (10):
  USB: f81232: rename private struct member name
  USB: f81232: implement RX bulk-in EP
  USB: f81232: change lock mechanism
  USB: f81232: implement read IIR/MSR with endpoint
  USB: f81232: implement MCR/MSR function
  USB: f81232: implement port enable/disable method
  USB: f81232: implement set_termios()
  USB: f81232: clarify f81232_ioctl() and fix
  USB: f81232: cleanup non-used define
  USB: f81232: modify/add author

 drivers/usb/serial/f81232.c | 555 
 1 file changed, 457 insertions(+), 98 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V9 05/10] USB: f81232: implement MCR/MSR function

2015-03-17 Thread Peter Hung
This patch implement relative MCR/MSR function, such like
tiocmget()/tiocmset()/dtr_rts()/carrier_raised()

original f81232_carrier_raised() compared with wrong value UART_DCD.
It's should compared with UART_MSR_DCD.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 139 +---
 1 file changed, 117 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 1e1261f..28759a0 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -34,8 +34,10 @@ MODULE_DEVICE_TABLE(usb, id_table);
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST0xa0
 #define F81232_GET_REGISTER0xc0
+#define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
 #define CONTROL_DTR0x01
@@ -54,7 +56,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 
 struct f81232_private {
struct mutex lock;
-   u8 line_control;
+   u8 modem_control;
u8 modem_status;
struct work_struct interrupt_work;
struct usb_serial_port *port;
@@ -95,6 +97,42 @@ static int f81232_get_register(struct usb_serial_port *port, 
u16 reg, u8 *val)
return status;
 }
 
+static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val)
+{
+   int status;
+   u8 *tmp;
+   struct usb_device *dev = port->serial->dev;
+
+   tmp = kmalloc(sizeof(val), GFP_KERNEL);
+   if (!tmp)
+   return -ENOMEM;
+
+   *tmp = val;
+
+   status = usb_control_msg(dev,
+   usb_sndctrlpipe(dev, 0),
+   F81232_REGISTER_REQUEST,
+   F81232_SET_REGISTER,
+   reg,
+   0,
+   tmp,
+   sizeof(val),
+   USB_CTRL_SET_TIMEOUT);
+   if (status != sizeof(val)) {
+   dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
+
+   if (status < 0)
+   status = usb_translate_errors(status);
+   else
+   status = -EIO;
+   } else {
+   status = 0;
+   }
+
+   kfree(tmp);
+   return status;
+}
+
 static void f81232_read_msr(struct usb_serial_port *port)
 {
int status;
@@ -139,6 +177,51 @@ static void f81232_read_msr(struct usb_serial_port *port)
mutex_unlock(&priv->lock);
 }
 
+static int f81232_set_mctrl(struct usb_serial_port *port,
+  unsigned int set, unsigned int clear)
+{
+   u8 val;
+   int status;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0)
+   return 0;   /* no change */
+
+   /* 'set' takes precedence over 'clear' */
+   clear &= ~set;
+
+   /* force enable interrupt with OUT2 */
+   mutex_lock(&priv->lock);
+   val = UART_MCR_OUT2 | priv->modem_control;
+
+   if (clear & TIOCM_DTR)
+   val &= ~UART_MCR_DTR;
+
+   if (clear & TIOCM_RTS)
+   val &= ~UART_MCR_RTS;
+
+   if (set & TIOCM_DTR)
+   val |= UART_MCR_DTR;
+
+   if (set & TIOCM_RTS)
+   val |= UART_MCR_RTS;
+
+   dev_dbg(&port->dev, "%s new:%02x old:%02x\n", __func__,
+   val, priv->modem_control);
+
+   status = f81232_set_register(port, MODEM_CONTROL_REGISTER, val);
+   if (status) {
+   dev_err(&port->dev, "%s set MCR status < 0\n", __func__);
+   mutex_unlock(&priv->lock);
+   return status;
+   }
+
+   priv->modem_control = val;
+   mutex_unlock(&priv->lock);
+
+   return 0;
+}
+
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
  size_t actual_length)
@@ -254,12 +337,6 @@ static void f81232_process_read_urb(struct urb *urb)
tty_flip_buffer_push(&port->port);
 }
 
-static int set_control_lines(struct usb_device *dev, u8 value)
-{
-   /* FIXME - Stubbed out for now */
-   return 0;
-}
-
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
/* FIXME - Stubbed out for now */
@@ -287,15 +364,35 @@ static void f81232_set_termios(struct tty_struct *tty,
 
 static int f81232_tiocmget(struct tty_struct *tty)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int r;
+   struct usb_serial_port *port 

[PATCH V9 06/10] USB: f81232: implement port enable/disable method

2015-03-17 Thread Peter Hung
We put FCR/IER initial step to f81232_port_enable()/f81232_port_disable().
When port is open, it set MSR interrupt on. Otherwise set it off.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 49 +
 1 file changed, 49 insertions(+)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 28759a0..f0109a4 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -37,6 +37,8 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
@@ -348,6 +350,48 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 */
 }
 
+static int f81232_port_enable(struct usb_serial_port *port)
+{
+   u8 val;
+   int status;
+
+   /* fifo on, trigger8, clear TX/RX*/
+   val = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+   UART_FCR_CLEAR_XMIT;
+
+   status = f81232_set_register(port, FIFO_CONTROL_REGISTER, val);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set FCR: %d\n",
+   __func__, status);
+   return status;
+   }
+
+   /* MSR Interrupt only, LSR will read from Bulk-in odd byte */
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER,
+   UART_IER_MSI);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set IER: %d\n",
+   __func__, status);
+   return status;
+   }
+
+   return 0;
+}
+
+static int f81232_port_disable(struct usb_serial_port *port)
+{
+   int status;
+
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, 0);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set IER: %d\n",
+   __func__, status);
+   return status;
+   }
+
+   return 0;
+}
+
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -399,6 +443,10 @@ static int f81232_open(struct tty_struct *tty, struct 
usb_serial_port *port)
 {
int result;
 
+   result = f81232_port_enable(port);
+   if (result)
+   return result;
+
/* Setup termios */
if (tty)
f81232_set_termios(tty, port, NULL);
@@ -421,6 +469,7 @@ static int f81232_open(struct tty_struct *tty, struct 
usb_serial_port *port)
 
 static void f81232_close(struct usb_serial_port *port)
 {
+   f81232_port_disable(port);
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V9 08/10] USB: f81232: clarify f81232_ioctl() and fix

2015-03-17 Thread Peter Hung
We extract TIOCGSERIAL section in f81232_ioctl() to f81232_get_serial_info()
to make it clarify.

Also we fix device type from 16654 to 16550A, and set it's baud_base
to 115200 (1.8432MHz/16).

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 30 +++---
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 6be37f3..0da16ce 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -600,24 +600,32 @@ static int f81232_carrier_raised(struct usb_serial_port 
*port)
return 0;
 }
 
+static int f81232_get_serial_info(struct usb_serial_port *port,
+   unsigned long arg)
+{
+   struct serial_struct ser;
+
+   memset(&ser, 0, sizeof(ser));
+
+   ser.type = PORT_16550A;
+   ser.line = port->minor;
+   ser.port = port->port_number;
+   ser.baud_base = F81232_MAX_BAUDRATE;
+
+   if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
+   return -EFAULT;
+
+   return 0;
+}
+
 static int f81232_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
 {
-   struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
 
switch (cmd) {
case TIOCGSERIAL:
-   memset(&ser, 0, sizeof ser);
-   ser.type = PORT_16654;
-   ser.line = port->minor;
-   ser.port = port->port_number;
-   ser.baud_base = 460800;
-
-   if (copy_to_user((void __user *)arg, &ser, sizeof ser))
-   return -EFAULT;
-
-   return 0;
+   return f81232_get_serial_info(port, arg);
default:
break;
}
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V9 09/10] USB: f81232: cleanup non-used define

2015-03-17 Thread Peter Hung
We remove non-used define in this patch to avoid wrong usage.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 14 --
 1 file changed, 14 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 0da16ce..a0e0b9d 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,20 +47,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
-#define CONTROL_DTR0x01
-#define CONTROL_RTS0x02
-
-#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
-
 struct f81232_private {
struct mutex lock;
u8 modem_control;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V9 07/10] USB: f81232: implement set_termios()

2015-03-17 Thread Peter Hung
The original driver had do not any h/w change in driver.
This patch implements with configure H/W for
baud/parity/word length/stop bits functional in f81232_set_termios().

This patch also implement DTR/RTS control when baudrate B0.
We drop DTR/RTS when B0, otherwise enable it.

We are checking baudrate in set_termios() too, If baudrate larger then 115200,
it will be changed to 115200 and use tty_encode_baud_rate() to encode into tty

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 112 ++--
 1 file changed, 108 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index f0109a4..6be37f3 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -31,14 +31,19 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* Maximum baudrate for F81232 */
+#define F81232_MAX_BAUDRATE115200
+
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST0xa0
 #define F81232_GET_REGISTER0xc0
 #define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
 #define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
 #define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
@@ -64,6 +69,11 @@ struct f81232_private {
struct usb_serial_port *port;
 };
 
+static int calc_baud_divisor(speed_t baudrate)
+{
+   return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate);
+}
+
 static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
 {
int status;
@@ -350,6 +360,53 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 */
 }
 
+static void f81232_set_baudrate(struct usb_serial_port *port, speed_t baudrate)
+{
+   u8 lcr;
+   int divisor, status = 0;
+
+   divisor = calc_baud_divisor(baudrate);
+
+   status = f81232_get_register(port, LINE_CONTROL_REGISTER,
+&lcr); /* get LCR */
+   if (status) {
+   dev_err(&port->dev, "%s failed to get LCR: %d\n",
+   __func__, status);
+   return;
+   }
+
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+lcr | UART_LCR_DLAB); /* Enable DLAB */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set DLAB: %d\n",
+   __func__, status);
+   return;
+   }
+
+   status = f81232_set_register(port, RECEIVE_BUFFER_REGISTER,
+divisor & 0x00ff); /* low */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set baudrate MSB: %d\n",
+   __func__, status);
+   goto reapply_lcr;
+   }
+
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER,
+(divisor & 0xff00) >> 8); /* high */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set baudrate LSB: %d\n",
+   __func__, status);
+   }
+
+reapply_lcr:
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+   lcr & ~UART_LCR_DLAB);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set DLAB: %d\n",
+   __func__, status);
+   }
+}
+
 static int f81232_port_enable(struct usb_serial_port *port)
 {
u8 val;
@@ -395,15 +452,62 @@ static int f81232_port_disable(struct usb_serial_port 
*port)
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
 {
-   /* FIXME - Stubbed out for now */
+   u8 new_lcr = 0;
+   int status = 0;
+   speed_t baudrate;
 
/* Don't change anything if nothing has changed */
if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
 
-   /* Do the real work here... */
-   if (old_termios)
-   tty_termios_copy_hw(&tty->termios, old_termios);
+   if (C_BAUD(tty) == B0)
+   f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
+   else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+   f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0);
+
+   baudrate = tty_get_baud_rate(tty);
+   if (baudrate > 0) {
+   if (baudrate > F81232_MAX_BAUDRATE) {
+   baudrate = F81232_MAX_BAUDRATE;
+   tty_encode_baud_rate(tty, b

[PATCH V9 10/10] USB: f81232: modify/add author

2015-03-17 Thread Peter Hung
Add me to co-author and fix no '>' in greg kh's email

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index a0e0b9d..54cc707 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -688,5 +688,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
-MODULE_AUTHOR("Greg Kroah-Hartman ");
+MODULE_AUTHOR("Peter Hong ");
 MODULE_LICENSE("GPL v2");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V8 04/10] USB: f81232: implement read IIR/MSR with endpoint

2015-03-16 Thread Peter Hung

Hello,

Johan Hovold 於 2015/3/16 下午 04:55 寫道:

On Mon, Mar 16, 2015 at 11:08:29AM +0800, Peter Hung wrote:

Could you rewrite this as

if (status < 0)
status = usb_translate_errors(status);
else
status = 0;


In my definition the return value of set/getregister(), 0 is success,
negative values are errors. The function usb_control_msg() return value
is success transmited/received byte. It's maybe return 0. I want to
treat 0 with error(-EIO). But if pass 0 to usb_translate_errors(), It
will return 0 back. So I need especially handle with status == 0.


I meant to write

if (status < 0)
status = usb_translate_errors(status);
else
status = -EIO;

which I think is more readable.


It's looks more readable of the style that you mentioned.
Thanks for your advice, I'll add it with next patch.

--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V8 02/10] USB: f81232: implement RX bulk-in EP

2015-03-16 Thread Peter Hung

Hello,

Johan Hovold 於 2015/3/16 下午 04:52 寫道:

On Mon, Mar 16, 2015 at 10:53:38AM +0800, Peter Hung wrote:

To avoid confusing to user, I'll keep it without warning message.


Yes, skip the warning, but could you a short comment about this (e.g.
the 1-byte packet on open) before you do the size check?


Thanks for your mention, I will add it for next patch.

--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V8 04/10] USB: f81232: implement read IIR/MSR with endpoint

2015-03-15 Thread Peter Hung

Hello,

Johan Hovold 於 2015/3/14 下午 08:02 寫道:

On Thu, Feb 26, 2015 at 06:02:10PM +0800, Peter Hung wrote:

+   if (status != sizeof(*val)) {
+   dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
+
+   if (status == 0)
+   status = -EIO;
+   else
+   status = usb_translate_errors(status);


Could you rewrite this as

if (status < 0)
status = usb_translate_errors(status);
else
status = 0;


In my definition the return value of set/getregister(), 0 is success, 
negative values are errors. The function usb_control_msg() return value 
is success transmited/received byte. It's maybe return 0. I want to 
treat 0 with error(-EIO). But if pass 0 to usb_translate_errors(), It 
will return 0 back. So I need especially handle with status == 0.


I'll keep this sections.

Thanks for review
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V8 02/10] USB: f81232: implement RX bulk-in EP

2015-03-15 Thread Peter Hung

Hello,

Johan Hovold 於 2015/3/14 下午 07:48 寫道:

On Thu, Feb 26, 2015 at 06:02:08PM +0800, Peter Hung wrote:

-   if (!urb->actual_length)
+   if ((urb->actual_length < 2) || (urb->actual_length % 2))
return;


Not parsing short data (e.g. not divisible by 2) is OK I guess. You
could also just discard the last odd byte, but that's up to you.

Either way, I think you should add a dev_warn here rather than just
silently drop it.


With F81232, when it first submit with interrupt URB, it will response 
once with 1 bytes data. The data is hw current LSR, but it useless on 
open. It's should necessary with receiving data. When the device is 
working good, it's should acked with even size data.


To avoid confusing to user, I'll keep it without warning message.

Thanks
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/2] serial: 8250_pci: Fintek products patches

2015-03-15 Thread Peter Hung

Hello,

Greg KH 於 2015/3/15 下午 05:25 寫道:

Why did you cc: the linux-usb@vger mailing list on these?  Don't you
mean linux-serial@vger?



Sorry for my fault. Should I resend it with correct mail-list with V2 ??
or just send this series patches ?

Thanks
--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] serial: 8250_pci: remove non-used var for F81504

2015-03-12 Thread Peter Hung
Remove pci_fintek_setup() non-used var with calculation ciobase

Signed-off-by: Peter Hung 
---
 drivers/tty/serial/8250/8250_pci.c | 11 ++-
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c 
b/drivers/tty/serial/8250/8250_pci.c
index 892eb32..701b7b1 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1550,9 +1550,7 @@ static int pci_fintek_setup(struct serial_private *priv,
struct uart_8250_port *port, int idx)
 {
struct pci_dev *pdev = priv->dev;
-   unsigned long base;
unsigned long iobase;
-   unsigned long ciobase = 0;
u8 config_base;
u32 bar_data[3];
 
@@ -1601,11 +1599,6 @@ static int pci_fintek_setup(struct serial_private *priv,
return -EINVAL;
}
 
-   if (idx < 4) {
-   base = pci_resource_start(priv->dev, 3);
-   ciobase = (int)(base + (0x8 * idx));
-   }
-
/* Get the io address dispatch from the BIOS */
pci_read_config_dword(pdev, 0x24, &bar_data[0]);
pci_read_config_dword(pdev, 0x20, &bar_data[1]);
@@ -1614,8 +1607,8 @@ static int pci_fintek_setup(struct serial_private *priv,
/* Calculate Real IO Port */
iobase = (bar_data[idx/4] & 0xffe0) + (idx % 4) * 8;
 
-   dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx 
config_base=0x%2x\n",
-   __func__, idx, iobase, ciobase, config_base);
+   dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx config_base=0x%2x\n",
+   __func__, idx, iobase, config_base);
 
/* Enable UART I/O port */
pci_write_config_byte(pdev, config_base + 0x00, 0x01);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/2] serial: 8250_pci: Fintek products patches

2015-03-12 Thread Peter Hung
These series patches works for Fintek F81504/F81508/F81512 PCI to Serial Port.
and patch 0002 is following with patch 0001.

patch 0001 is just cleanup non-used source code.
patch 0002 is major patch.

The serial port of our product will failed after wakeup from S3(STR).

It's due to when the system wakeup from S3(STR), this PCI device's
configuration space from 0x40 to 0x40 + max_port * 0x08 should be
re-configured. If had no re-configure, It's will all zero.

We move all initialization from pci_fintek_setup() to pci_fintek_init() and
set it to pci_serial_quirks struct .init section. It's will re-init this 
device when system wakeup from pciserial_resume_ports().

Peter Hung (2):
  serial: 8250_pci: remove non-used var for F81504
  serial: 8250_pci: port failed after wakeup from S3

 drivers/tty/serial/8250/8250_pci.c | 121 +++--
 1 file changed, 50 insertions(+), 71 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] serial: 8250_pci: port failed after wakeup from S3

2015-03-12 Thread Peter Hung
Serial ports of F81504/F81508/F81512 will failed when wakeup from S3(STR).

It's due to when the system wakeup from S3(STR), this PCI device's
configuration space from 0x40 to 0x40 + max_port * 0x08 should be
re-configured.

We move all initialization from pci_fintek_setup() to pci_fintek_init() and
set it to pci_serial_quirks .init section. It's will re-init this device when
system wakeup from pciserial_resume_ports().

Signed-off-by: Peter Hung 
---
 drivers/tty/serial/8250/8250_pci.c | 114 -
 1 file changed, 50 insertions(+), 64 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c 
b/drivers/tty/serial/8250/8250_pci.c
index 701b7b1..cfa477f 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1545,91 +1545,74 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
return ret;
 }
 
-static int pci_fintek_setup(struct serial_private *priv,
-   const struct pciserial_board *board,
-   struct uart_8250_port *port, int idx)
+static int pci_fintek_init(struct pci_dev *dev)
 {
-   struct pci_dev *pdev = priv->dev;
unsigned long iobase;
-   u8 config_base;
+   u32 max_port, i;
u32 bar_data[3];
+   u8 config_base;
 
-   /*
-* Find each UARTs offset in PCI configuraion space
-*/
-   switch (idx) {
-   case 0:
-   config_base = 0x40;
-   break;
-   case 1:
-   config_base = 0x48;
-   break;
-   case 2:
-   config_base = 0x50;
-   break;
-   case 3:
-   config_base = 0x58;
-   break;
-   case 4:
-   config_base = 0x60;
-   break;
-   case 5:
-   config_base = 0x68;
+   switch (dev->device) {
+   case 0x1104: /* 4 ports */
+   case 0x1108: /* 8 ports */
+   max_port = dev->device & 0xff;
break;
-   case 6:
-   config_base = 0x70;
-   break;
-   case 7:
-   config_base = 0x78;
-   break;
-   case 8:
-   config_base = 0x80;
-   break;
-   case 9:
-   config_base = 0x88;
-   break;
-   case 10:
-   config_base = 0x90;
-   break;
-   case 11:
-   config_base = 0x98;
+   case 0x1112: /* 12 ports */
+   max_port = 12;
break;
default:
-   /* Unknown number of ports, get out of here */
return -EINVAL;
}
 
/* Get the io address dispatch from the BIOS */
-   pci_read_config_dword(pdev, 0x24, &bar_data[0]);
-   pci_read_config_dword(pdev, 0x20, &bar_data[1]);
-   pci_read_config_dword(pdev, 0x1c, &bar_data[2]);
+   pci_read_config_dword(dev, 0x24, &bar_data[0]);
+   pci_read_config_dword(dev, 0x20, &bar_data[1]);
+   pci_read_config_dword(dev, 0x1c, &bar_data[2]);
+
+   for (i = 0; i < max_port; ++i) {
+   /* UART0 configuration offset start from 0x40 */
+   config_base = 0x40 + 0x08 * i;
+
+   /* Calculate Real IO Port */
+   iobase = (bar_data[i / 4] & 0xffe0) + (i % 4) * 8;
+
+   /* Enable UART I/O port */
+   pci_write_config_byte(dev, config_base + 0x00, 0x01);
+
+   /* Select 128-byte FIFO and 8x FIFO threshold */
+   pci_write_config_byte(dev, config_base + 0x01, 0x33);
 
-   /* Calculate Real IO Port */
-   iobase = (bar_data[idx/4] & 0xffe0) + (idx % 4) * 8;
+   /* LSB UART */
+   pci_write_config_byte(dev, config_base + 0x04,
+   (u8)(iobase & 0xff));
 
-   dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx config_base=0x%2x\n",
-   __func__, idx, iobase, config_base);
+   /* MSB UART */
+   pci_write_config_byte(dev, config_base + 0x05,
+   (u8)((iobase & 0xff00) >> 8));
 
-   /* Enable UART I/O port */
-   pci_write_config_byte(pdev, config_base + 0x00, 0x01);
+   pci_write_config_byte(dev, config_base + 0x06, dev->irq);
+   }
+
+   return max_port;
+}
 
-   /* Select 128-byte FIFO and 8x FIFO threshold */
-   pci_write_config_byte(pdev, config_base + 0x01, 0x33);
+static int pci_fintek_setup(struct serial_private *priv,
+   const struct pciserial_board *board,
+   struct uart_8250_port *port, int idx)
+{
+   struct pci_dev *pdev = priv->dev;
+   u8 config_base;
+   u16 iobase;
 
-   /* LSB UART */
-   pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff));
+   config_base = 0x40 + 0x08 * idx;
 
-   /* MSB UART */
- 

Re: [PATCH V8 00/10] USB: f81232: V8 patches

2015-03-04 Thread Peter Hung

Hello,

Peter Hung 於 2015/2/26 下午 06:02 寫道:

This series patch V8 is changed from V7 as following:

1. The V7 MSR strange delta value is checked with locking problem. We changed
f81232_set_mctrl() & f81232_read_msr() lock mechanism, the old version is
only locked with variable protection, new version will lock from start to
end with these 2 function.
2. f81232_set_baudrate() add error handling and no longer handle with baudrate
B0, change to handle with f81232_set_termios()
3. When user set baudrate larger then 115200, we will change it with 115200
and tty_encode_baud_rate() in f81232_set_termios().
4. V7 f81232_set_baudrate() divisor declared with type u8, it will make
baudrate set failed with smaller then B600 (115200/300=384 overflow :Q).
We changed it with integer type for divisor larger then 256.



Did you received the series of F81232 V8 patches ? Please tell me if
not received.

Thanks for your review.

--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 01/10] USB: f81232: rename private struct member name

2015-02-26 Thread Peter Hung
Change private struct member name from line_status to modem_status.
It will store MSR for some functions used

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c5dc233..669a2f2 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,7 +47,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 struct f81232_private {
spinlock_t lock;
u8 line_control;
-   u8 line_status;
+   u8 modem_status;
 };
 
 static void f81232_update_line_status(struct usb_serial_port *port,
@@ -113,8 +113,8 @@ static void f81232_process_read_urb(struct urb *urb)
 
/* update line status */
spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->line_status;
-   priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+   line_status = priv->modem_status;
+   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
 
if (!urb->actual_length)
@@ -241,7 +241,7 @@ static void f81232_dtr_rts(struct usb_serial_port *port, 
int on)
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   if (priv->line_status & UART_DCD)
+   if (priv->modem_status & UART_DCD)
return 1;
return 0;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 03/10] USB: f81232: change lock mechanism

2015-02-26 Thread Peter Hung
The original driver lock with spin_lock_irqsave()/spin_unlock_irqrestore()
because of it's maybe used in interrupt context f81232_process_read_urb().

We had remove it from previous patch "implement RX bulk-in EP", so we can
change it from busying loop spin_lock to sleepable mutex_lock.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 25b1a47..cf5b902 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -19,7 +19,7 @@
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -46,7 +46,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define UART_CTS   0x80
 
 struct f81232_private {
-   spinlock_t lock;
+   struct mutex lock;
u8 line_control;
u8 modem_status;
 };
@@ -227,17 +227,16 @@ static void f81232_close(struct usb_serial_port *port)
 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   unsigned long flags;
u8 control;
 
-   spin_lock_irqsave(&priv->lock, flags);
+   mutex_lock(&priv->lock);
/* Change DTR and RTS */
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);
+   mutex_unlock(&priv->lock);
set_control_lines(port->serial->dev, control);
 }
 
@@ -281,7 +280,7 @@ static int f81232_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;
 
-   spin_lock_init(&priv->lock);
+   mutex_init(&priv->lock);
 
usb_set_serial_port_data(port, priv);
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 02/10] USB: f81232: implement RX bulk-in EP

2015-02-26 Thread Peter Hung
The F81232 bulk-in is RX data + LSR channel, data format is
[LSR+Data][LSR+Data]. , We had implemented in f81232_process_read_urb().

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 71 +++--
 1 file changed, 37 insertions(+), 34 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 669a2f2..25b1a47 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 
 static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1934, 0x0706) },
@@ -104,44 +105,46 @@ exit:
 static void f81232_process_read_urb(struct urb *urb)
 {
struct usb_serial_port *port = urb->context;
-   struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
-   char tty_flag = TTY_NORMAL;
-   unsigned long flags;
-   u8 line_status;
-   int i;
-
-   /* update line status */
-   spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->modem_status;
-   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
-   spin_unlock_irqrestore(&priv->lock, flags);
+   char tty_flag;
+   unsigned int i;
+   u8 lsr;
 
-   if (!urb->actual_length)
+   if ((urb->actual_length < 2) || (urb->actual_length % 2))
return;
 
-   /* break takes precedence over parity, */
-   /* which takes precedence over framing errors */
-   if (line_status & UART_BREAK_ERROR)
-   tty_flag = TTY_BREAK;
-   else if (line_status & UART_PARITY_ERROR)
-   tty_flag = TTY_PARITY;
-   else if (line_status & UART_FRAME_ERROR)
-   tty_flag = TTY_FRAME;
-   dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
-
-   /* overrun is special, not associated with a char */
-   if (line_status & UART_OVERRUN_ERROR)
-   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
-   if (port->port.console && port->sysrq) {
-   for (i = 0; i < urb->actual_length; ++i)
-   if (!usb_serial_handle_sysrq_char(port, data[i]))
-   tty_insert_flip_char(&port->port, data[i],
-   tty_flag);
-   } else {
-   tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
-   urb->actual_length);
+   /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
+
+   for (i = 0; i < urb->actual_length; i += 2) {
+   tty_flag = TTY_NORMAL;
+   lsr = data[i];
+
+   if (lsr & UART_LSR_BRK_ERROR_BITS) {
+   if (lsr & UART_LSR_BI) {
+   tty_flag = TTY_BREAK;
+   port->icount.brk++;
+   usb_serial_handle_break(port);
+   } else if (lsr & UART_LSR_PE) {
+   tty_flag = TTY_PARITY;
+   port->icount.parity++;
+   } else if (lsr & UART_LSR_FE) {
+   tty_flag = TTY_FRAME;
+   port->icount.frame++;
+   }
+
+   if (lsr & UART_LSR_OE) {
+   port->icount.overrun++;
+   tty_insert_flip_char(&port->port, 0,
+   TTY_OVERRUN);
+   }
+   }
+
+   if (port->port.console && port->sysrq) {
+   if (usb_serial_handle_sysrq_char(port, data[i + 1]))
+   continue;
+   }
+
+   tty_insert_flip_char(&port->port, data[i + 1], tty_flag);
}
 
tty_flip_buffer_push(&port->port);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 05/10] USB: f81232: implement MCR/MSR function

2015-02-26 Thread Peter Hung
This patch implement relative MCR/MSR function, such like
tiocmget()/tiocmset()/dtr_rts()/carrier_raised()

original f81232_carrier_raised() compared with wrong value UART_DCD.
It's should compared with UART_MSR_DCD.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 139 +---
 1 file changed, 117 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 46a81ef..b70f9b9 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -34,8 +34,10 @@ MODULE_DEVICE_TABLE(usb, id_table);
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST0xa0
 #define F81232_GET_REGISTER0xc0
+#define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
 #define CONTROL_DTR0x01
@@ -54,7 +56,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 
 struct f81232_private {
struct mutex lock;
-   u8 line_control;
+   u8 modem_control;
u8 modem_status;
struct work_struct interrupt_work;
struct usb_serial_port *port;
@@ -95,6 +97,42 @@ static int f81232_get_register(struct usb_serial_port *port, 
u16 reg, u8 *val)
return status;
 }
 
+static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val)
+{
+   int status;
+   u8 *tmp;
+   struct usb_device *dev = port->serial->dev;
+
+   tmp = kmalloc(sizeof(val), GFP_KERNEL);
+   if (!tmp)
+   return -ENOMEM;
+
+   *tmp = val;
+
+   status = usb_control_msg(dev,
+   usb_sndctrlpipe(dev, 0),
+   F81232_REGISTER_REQUEST,
+   F81232_SET_REGISTER,
+   reg,
+   0,
+   tmp,
+   sizeof(u8),
+   USB_CTRL_SET_TIMEOUT);
+   if (status != sizeof(val)) {
+   dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
+
+   if (status == 0)
+   status = -EIO;
+   else
+   status = usb_translate_errors(status);
+   } else {
+   status = 0;
+   }
+
+   kfree(tmp);
+   return status;
+}
+
 static void f81232_read_msr(struct usb_serial_port *port)
 {
int status;
@@ -139,6 +177,51 @@ static void f81232_read_msr(struct usb_serial_port *port)
mutex_unlock(&priv->lock);
 }
 
+static int f81232_set_mctrl(struct usb_serial_port *port,
+  unsigned int set, unsigned int clear)
+{
+   u8 urb_value;
+   int status;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0)
+   return 0;   /* no change */
+
+   /* 'set' takes precedence over 'clear' */
+   clear &= ~set;
+
+   /* force enable interrupt with OUT2 */
+   mutex_lock(&priv->lock);
+   urb_value = UART_MCR_OUT2 | priv->modem_control;
+
+   if (clear & TIOCM_DTR)
+   urb_value &= ~UART_MCR_DTR;
+
+   if (clear & TIOCM_RTS)
+   urb_value &= ~UART_MCR_RTS;
+
+   if (set & TIOCM_DTR)
+   urb_value |= UART_MCR_DTR;
+
+   if (set & TIOCM_RTS)
+   urb_value |= UART_MCR_RTS;
+
+   dev_dbg(&port->dev, "%s new:%02x old:%02x\n", __func__,
+   urb_value, priv->modem_control);
+
+   status = f81232_set_register(port, MODEM_CONTROL_REGISTER, urb_value);
+   if (status) {
+   dev_err(&port->dev, "%s set MCR status < 0\n", __func__);
+   mutex_unlock(&priv->lock);
+   return status;
+   }
+
+   priv->modem_control = urb_value;
+   mutex_unlock(&priv->lock);
+
+   return 0;
+}
+
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
  size_t actual_length)
@@ -250,12 +333,6 @@ static void f81232_process_read_urb(struct urb *urb)
tty_flip_buffer_push(&port->port);
 }
 
-static int set_control_lines(struct usb_device *dev, u8 value)
-{
-   /* FIXME - Stubbed out for now */
-   return 0;
-}
-
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
/* FIXME - Stubbed out for now */
@@ -283,15 +360,35 @@ static void f81232_set_termios(struct tty_struct *tty,
 
 static int f81232_tiocmget(struct tty_struct *tty)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int r;
+   struct usb_serial_port *port = t

[PATCH V8 04/10] USB: f81232: implement read IIR/MSR with endpoint

2015-02-26 Thread Peter Hung
The interrupt endpoint will report current IIR. If we got IIR with MSR changed
, We will do read MSR with interrupt_work worker to do f81232_read_msr()
function.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 126 +---
 1 file changed, 118 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index cf5b902..46a81ef 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -31,6 +31,13 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* USB Control EP parameter */
+#define F81232_REGISTER_REQUEST0xa0
+#define F81232_GET_REGISTER0xc0
+
+#define SERIAL_BASE_ADDRESS0x0120
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
+
 #define CONTROL_DTR0x01
 #define CONTROL_RTS0x02
 
@@ -49,19 +56,112 @@ struct f81232_private {
struct mutex lock;
u8 line_control;
u8 modem_status;
+   struct work_struct interrupt_work;
+   struct usb_serial_port *port;
 };
 
+static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
+{
+   int status;
+   u8 *tmp;
+   struct usb_device *dev = port->serial->dev;
+
+   tmp = kmalloc(sizeof(*val), GFP_KERNEL);
+   if (!tmp)
+   return -ENOMEM;
+
+   status = usb_control_msg(dev,
+   usb_rcvctrlpipe(dev, 0),
+   F81232_REGISTER_REQUEST,
+   F81232_GET_REGISTER,
+   reg,
+   0,
+   tmp,
+   sizeof(u8),
+   USB_CTRL_GET_TIMEOUT);
+   if (status != sizeof(*val)) {
+   dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
+
+   if (status == 0)
+   status = -EIO;
+   else
+   status = usb_translate_errors(status);
+   } else {
+   status = 0;
+   *val = *tmp;
+   }
+
+   kfree(tmp);
+   return status;
+}
+
+static void f81232_read_msr(struct usb_serial_port *port)
+{
+   int status;
+   u8 current_msr;
+   struct tty_struct *tty;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   mutex_lock(&priv->lock);
+   status = f81232_get_register(port, MODEM_STATUS_REGISTER,
+   ¤t_msr);
+   if (status) {
+   dev_err(&port->dev, "%s fail, status: %d\n", __func__, status);
+   mutex_unlock(&priv->lock);
+   return;
+   }
+
+   if (!(current_msr & UART_MSR_ANY_DELTA)) {
+   mutex_unlock(&priv->lock);
+   return;
+   }
+
+   priv->modem_status = current_msr;
+
+   if (current_msr & UART_MSR_DCTS)
+   port->icount.cts++;
+   if (current_msr & UART_MSR_DDSR)
+   port->icount.dsr++;
+   if (current_msr & UART_MSR_TERI)
+   port->icount.rng++;
+   if (current_msr & UART_MSR_DDCD) {
+   port->icount.dcd++;
+   tty = tty_port_tty_get(&port->port);
+   if (tty) {
+   usb_serial_handle_dcd_change(port, tty,
+   current_msr & UART_MSR_DCD);
+
+   tty_kref_put(tty);
+   }
+   }
+
+   wake_up_interruptible(&port->port.delta_msr_wait);
+   mutex_unlock(&priv->lock);
+}
+
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
- unsigned int actual_length)
+ size_t actual_length)
 {
-   /*
-* FIXME: Update port->icount, and call
-*
-*  wake_up_interruptible(&port->port.delta_msr_wait);
-*
-*on MSR changes.
-*/
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (!actual_length)
+   return;
+
+   switch (data[0] & 0x07) {
+   case 0x00: /* msr change */
+   dev_dbg(&port->dev, "IIR: MSR Change: %02x\n", data[0]);
+   schedule_work(&priv->interrupt_work);
+   break;
+   case 0x02: /* tx-empty */
+   break;
+   case 0x04: /* rx data available */
+   break;
+   case 0x06: /* lsr change */
+   /* we can forget it. the LSR will read from bulk-in */
+   dev_dbg(&port->dev, "IIR: LSR Change: %02x\n", data[0]);
+   break;
+   }
 }
 
 static void f81232_read_int_callback(stru

[PATCH V8 07/10] USB: f81232: implement set_termios()

2015-02-26 Thread Peter Hung
The original driver had do not any h/w change in driver.
This patch implements with configure H/W for
baud/parity/word length/stop bits functional in f81232_set_termios().

This patch also implement DTR/RTS control when baudrate B0.
We drop DTR/RTS when B0, otherwise enable it.

We are checking baudrate in set_termios() too, If baudrate larger then 115200,
it will be changed to 115200 and use tty_encode_baud_rate() to encode into tty

f81232_set_baudrate() is also changed from V7. Add error handling when LCR get
failed or set LCR UART_LCR_DLAB failed. and older version, divisor is declared
with u8, it's will make failed with baudrate lower than 600 (115200/300=384).
We had changed divisor to int type.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 112 ++--
 1 file changed, 108 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index a3f9530..0580195 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -31,14 +31,19 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* Maximum baudrate for F81232 */
+#define F81232_MAX_BAUDRATE115200
+
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST0xa0
 #define F81232_GET_REGISTER0xc0
 #define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
 #define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
 #define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
@@ -64,6 +69,11 @@ struct f81232_private {
struct usb_serial_port *port;
 };
 
+static int calc_baud_divisor(speed_t baudrate)
+{
+   return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate);
+}
+
 static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
 {
int status;
@@ -346,6 +356,53 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 */
 }
 
+static void f81232_set_baudrate(struct usb_serial_port *port, speed_t baudrate)
+{
+   u8 lcr;
+   int divisor, status = 0;
+
+   divisor = calc_baud_divisor(baudrate);
+
+   status = f81232_get_register(port, LINE_CONTROL_REGISTER,
+&lcr); /* get LCR */
+   if (status) {
+   dev_err(&port->dev, "%s failed to get LCR: %d\n",
+   __func__, status);
+   return;
+   }
+
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+lcr | UART_LCR_DLAB); /* Enable DLAB */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set DLAB: %d\n",
+   __func__, status);
+   return;
+   }
+
+   status = f81232_set_register(port, RECEIVE_BUFFER_REGISTER,
+divisor & 0x00ff); /* low */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set baudrate MSB: %d\n",
+   __func__, status);
+   goto reapply_lcr;
+   }
+
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER,
+(divisor & 0xff00) >> 8); /* high */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set baudrate LSB: %d\n",
+   __func__, status);
+   }
+
+reapply_lcr:
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+   lcr & ~UART_LCR_DLAB);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set DLAB: %d\n",
+   __func__, status);
+   }
+}
+
 static int f81232_port_enable(struct usb_serial_port *port)
 {
u8 val;
@@ -391,15 +448,62 @@ static int f81232_port_disable(struct usb_serial_port 
*port)
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
 {
-   /* FIXME - Stubbed out for now */
+   u8 new_lcr = 0;
+   int status = 0;
+   speed_t baudrate;
 
/* Don't change anything if nothing has changed */
if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
 
-   /* Do the real work here... */
-   if (old_termios)
-   tty_termios_copy_hw(&tty->termios, old_termios);
+   if (C_BAUD(tty) == B0)
+   f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
+   else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+   f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0);
+
+   baudrate = tty_

[PATCH V8 06/10] USB: f81232: implement port enable/disable method

2015-02-26 Thread Peter Hung
We put FCR/IER initial step to f81232_port_enable()/f81232_port_disable().
When port is open, it set MSR interrupt on. Otherwise set it off.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 49 +
 1 file changed, 49 insertions(+)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index b70f9b9..a3f9530 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -37,6 +37,8 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
@@ -344,6 +346,48 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 */
 }
 
+static int f81232_port_enable(struct usb_serial_port *port)
+{
+   u8 val;
+   int status;
+
+   /* fifo on, trigger8, clear TX/RX*/
+   val = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+   UART_FCR_CLEAR_XMIT;
+
+   status = f81232_set_register(port, FIFO_CONTROL_REGISTER, val);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set FCR: %d\n",
+   __func__, status);
+   return status;
+   }
+
+   /* MSR Interrupt only, LSR will read from Bulk-in odd byte */
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER,
+   UART_IER_MSI);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set IER: %d\n",
+   __func__, status);
+   return status;
+   }
+
+   return 0;
+}
+
+static int f81232_port_disable(struct usb_serial_port *port)
+{
+   int status;
+
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, 0);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set IER: %d\n",
+   __func__, status);
+   return status;
+   }
+
+   return 0;
+}
+
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -395,6 +439,10 @@ static int f81232_open(struct tty_struct *tty, struct 
usb_serial_port *port)
 {
int result;
 
+   result = f81232_port_enable(port);
+   if (result)
+   return result;
+
/* Setup termios */
if (tty)
f81232_set_termios(tty, port, NULL);
@@ -417,6 +465,7 @@ static int f81232_open(struct tty_struct *tty, struct 
usb_serial_port *port)
 
 static void f81232_close(struct usb_serial_port *port)
 {
+   f81232_port_disable(port);
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 09/10] USB: f81232: cleanup non-used define

2015-02-26 Thread Peter Hung
We remove non-used define in this patch to avoid wrong usage.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 14 --
 1 file changed, 14 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 21f2342..0b7b69a 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,20 +47,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
-#define CONTROL_DTR0x01
-#define CONTROL_RTS0x02
-
-#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
-
 struct f81232_private {
struct mutex lock;
u8 modem_control;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 08/10] USB: f81232: clarify f81232_ioctl() and fix

2015-02-26 Thread Peter Hung
We extract TIOCGSERIAL section in f81232_ioctl() to f81232_get_serial_info()
to make it clarify.

Also we fix device type from 16654 to 16550A, and set it's baud_base
to 115200 (1.8432MHz/16).

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 30 +++---
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 0580195..21f2342 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -596,24 +596,32 @@ static int f81232_carrier_raised(struct usb_serial_port 
*port)
return 0;
 }
 
+static int f81232_get_serial_info(struct usb_serial_port *port,
+   unsigned long arg)
+{
+   struct serial_struct ser;
+
+   memset(&ser, 0, sizeof(ser));
+
+   ser.type = PORT_16550A;
+   ser.line = port->minor;
+   ser.port = port->port_number;
+   ser.baud_base = 115200;
+
+   if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
+   return -EFAULT;
+
+   return 0;
+}
+
 static int f81232_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
 {
-   struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
 
switch (cmd) {
case TIOCGSERIAL:
-   memset(&ser, 0, sizeof ser);
-   ser.type = PORT_16654;
-   ser.line = port->minor;
-   ser.port = port->port_number;
-   ser.baud_base = 460800;
-
-   if (copy_to_user((void __user *)arg, &ser, sizeof ser))
-   return -EFAULT;
-
-   return 0;
+   return f81232_get_serial_info(port, arg);
default:
break;
}
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 10/10] USB: f81232: modify/add author

2015-02-26 Thread Peter Hung
Add me to co-author and fix no '>' in greg kh's email

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 0b7b69a..65d5cf6 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -684,5 +684,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
-MODULE_AUTHOR("Greg Kroah-Hartman ");
+MODULE_AUTHOR("Peter Hong ");
 MODULE_LICENSE("GPL v2");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V8 00/10] USB: f81232: V8 patches

2015-02-26 Thread Peter Hung
This series patch V8 is changed from V7 as following:

1. The V7 MSR strange delta value is checked with locking problem. We changed
   f81232_set_mctrl() & f81232_read_msr() lock mechanism, the old version is
   only locked with variable protection, new version will lock from start to
   end with these 2 function.   
2. f81232_set_baudrate() add error handling and no longer handle with baudrate
   B0, change to handle with f81232_set_termios()
3. When user set baudrate larger then 115200, we will change it with 115200
   and tty_encode_baud_rate() in f81232_set_termios().
4. V7 f81232_set_baudrate() divisor declared with type u8, it will make 
   baudrate set failed with smaller then B600 (115200/300=384 overflow :Q).
   We changed it with integer type for divisor larger then 256.
   
V7 (old change):

1. The buffer of usb_control_msg() in set_register()/get_register() are change
   from local variable to kmalloc(). (PATCH V7 02/11)
2. Change all set_register()/get_register() return value 0 is success, 
   otherwise are failed. ( return 0 of usb_control_msg() treat as -EIO, 
   PATCH V7 02/11)
3. tty_port_tty_get() called only when DCD has changed. (PATCH V7 05/11)  
4. remove likely()/unlikely() branch prediction.
5. Implement DTR/RTS control when baudrate B0. We drop DTR/RTS when B0, 
   otherwise enable it. (PATCH V7 08/11)
6. Change private struct line_control to modem_control with meanful. 
   (PATCH V7 06/11)
7. We confirmd MSR strange delta value is not locking-issue. The issue
   maybe reproduce with set MCR & get MSR before IIR notice with MSR changed.
   
V6 (old change):

1. transform all function not to use private data as parameter, using
   usb_serial_port instead.
2. process_read_urb() add process of Break/FrameError/ParityError/OE.
   (patch: 03/10)
3. fix calc_baud_divisor() will cause divide by zero with B0. (patch: 04/10)
4. Some init step we extract it from set_termios() to f81232_port_init()
   and run it when open port only. (patch: 04/10)
5. We'll force re-read msr in tiocmget() because the IIR with MSR change
   maybe delay received. (patch: 05/10)
6. fix MSR status bits changed but delta bits is 0 will cause read serial port
   malfunctional with update port status. (patch: 08/10)
7. Add MSR change statistic when MSR has been read. (patch: 09/10)   
8. clarify a lot of code about Johan suggested.

Peter Hung (10):
  USB: f81232: rename private struct member name
  USB: f81232: implement RX bulk-in EP
  USB: f81232: change lock mechanism
  USB: f81232: implement read IIR/MSR with endpoint
  USB: f81232: implement MCR/MSR function
  USB: f81232: implement port enable/disable method
  USB: f81232: implement set_termios()
  USB: f81232: clarify f81232_ioctl() and fix
  USB: f81232: cleanup non-used define
  USB: f81232: modify/add author

 drivers/usb/serial/f81232.c | 551 
 1 file changed, 453 insertions(+), 98 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 00/11] USB: f81232: V7 patches

2015-02-24 Thread Peter Hung
This series patch V7 is changed from V6 as following:

1. The buffer of usb_control_msg() in set_register()/get_register() are change
   from local variable to kmalloc(). (PATCH V7 02/11)
2. Change all set_register()/get_register() return value 0 is success, 
   otherwise are failed. ( return 0 of usb_control_msg() treat as -EIO, 
   PATCH V7 02/11)
3. tty_port_tty_get() called only when DCD has changed. (PATCH V7 05/11)  
4. remove likely()/unlikely() branch prediction.
5. Implement DTR/RTS control when baudrate B0. We drop DTR/RTS when B0, 
   otherwise enable it. (PATCH V7 08/11)
6. Change private struct line_control to modem_control with meanful. 
   (PATCH V7 06/11)
7. We confirmd MSR strange delta value is not locking-issue. The issue
   maybe reproduce with set MCR & get MSR before IIR notice with MSR changed.
   
V6 (old change):

1. transform all function not to use private data as parameter, using
   usb_serial_port instead.
2. process_read_urb() add process of Break/FrameError/ParityError/OE.
   (patch: 03/10)
3. fix calc_baud_divisor() will cause divide by zero with B0. (patch: 04/10)
4. Some init step we extract it from set_termios() to f81232_port_init()
   and run it when open port only. (patch: 04/10)
5. We'll force re-read msr in tiocmget() because the IIR with MSR change
   maybe delay received. (patch: 05/10)
6. fix MSR status bits changed but delta bits is 0 will cause read serial port
   malfunctional with update port status. (patch: 08/10)
7. Add MSR change statistic when MSR has been read. (patch: 09/10)   
8. clarify a lot of code about Johan suggested.

Peter Hung (11):
  USB: f81232: rename private struct member name
  USB: f81232: add preparatory functions
  USB: f81232: implement RX bulk-in EP
  USB: f81232: change lock mechanism
  USB: f81232: implement read IIR/MSR with endpoint
  USB: f81232: implement MCR/MSR function
  USB: f81232: implement port_enable function
  USB: f81232: implement set_termios()
  USB: f81232: clarify f81232_ioctl() and fix
  USB: f81232: cleanup non-used define
  USB: f81232: modify/add author

 drivers/usb/serial/f81232.c | 554 
 1 file changed, 458 insertions(+), 96 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 04/11] USB: f81232: change lock mechanism

2015-02-24 Thread Peter Hung
The original driver lock with spin_lock_irqsave()/spin_unlock_irqrestore()
because of it's maybe used in interrupt context f81232_process_read_urb().

We had remove it from previous patch "implement RX bulk-in EP", so we can
change it from busying loop spin_lock to sleepable mutex_lock.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 419e2d6..bf072fe 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -19,7 +19,7 @@
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -51,7 +51,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define UART_CTS   0x80
 
 struct f81232_private {
-   spinlock_t lock;
+   struct mutex lock;
u8 line_control;
u8 modem_status;
 };
@@ -306,17 +306,16 @@ static void f81232_close(struct usb_serial_port *port)
 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   unsigned long flags;
u8 control;
 
-   spin_lock_irqsave(&priv->lock, flags);
+   mutex_lock(&priv->lock);
/* Change DTR and RTS */
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);
+   mutex_unlock(&priv->lock);
set_control_lines(port->serial->dev, control);
 }
 
@@ -360,7 +359,7 @@ static int f81232_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;
 
-   spin_lock_init(&priv->lock);
+   mutex_init(&priv->lock);
 
usb_set_serial_port_data(port, priv);
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 06/11] USB: f81232: implement MCR/MSR function

2015-02-24 Thread Peter Hung
This patch implement relative MCR/MSR function, such like
tiocmget()/tiocmset()/dtr_rts()/carrier_raised()

original f81232_carrier_raised() compared with wrong value UART_DCD.
It's should compared with UART_MSR_DCD.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 103 ++--
 1 file changed, 81 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 339be30..21f606f 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -37,6 +37,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
 #define CONTROL_DTR0x01
@@ -55,7 +56,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 
 struct f81232_private {
struct mutex lock;
-   u8 line_control;
+   u8 modem_control;
u8 modem_status;
struct work_struct interrupt_work;
struct usb_serial_port *port;
@@ -198,6 +199,52 @@ static void f81232_read_msr(struct usb_serial_port *port)
wake_up_interruptible(&port->port.delta_msr_wait);
 }
 
+static int f81232_set_mctrl(struct usb_serial_port *port,
+  unsigned int set, unsigned int clear)
+{
+   u8 urb_value;
+   int status;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0)
+   return 0;   /* no change */
+
+   /* 'set' takes precedence over 'clear' */
+   clear &= ~set;
+
+   /* force enable interrupt with OUT2 */
+   mutex_lock(&priv->lock);
+   urb_value = UART_MCR_OUT2 | priv->modem_control;
+   mutex_unlock(&priv->lock);
+
+   if (clear & TIOCM_DTR)
+   urb_value &= ~UART_MCR_DTR;
+
+   if (clear & TIOCM_RTS)
+   urb_value &= ~UART_MCR_RTS;
+
+   if (set & TIOCM_DTR)
+   urb_value |= UART_MCR_DTR;
+
+   if (set & TIOCM_RTS)
+   urb_value |= UART_MCR_RTS;
+
+   dev_dbg(&port->dev, "%s new:%02x old:%02x\n", __func__,
+   urb_value, priv->modem_control);
+
+   status = f81232_set_register(port, MODEM_CONTROL_REGISTER, urb_value);
+   if (status) {
+   dev_err(&port->dev, "%s set MCR status < 0\n", __func__);
+   return status;
+   } else {
+   mutex_lock(&priv->lock);
+   priv->modem_control = urb_value;
+   mutex_unlock(&priv->lock);
+   }
+
+   return 0;
+}
+
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
  size_t actual_length)
@@ -309,12 +356,6 @@ static void f81232_process_read_urb(struct urb *urb)
tty_flip_buffer_push(&port->port);
 }
 
-static int set_control_lines(struct usb_device *dev, u8 value)
-{
-   /* FIXME - Stubbed out for now */
-   return 0;
-}
-
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
/* FIXME - Stubbed out for now */
@@ -342,15 +383,35 @@ static void f81232_set_termios(struct tty_struct *tty,
 
 static int f81232_tiocmget(struct tty_struct *tty)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int r;
+   struct usb_serial_port *port = tty->driver_data;
+   struct f81232_private *port_priv = usb_get_serial_port_data(port);
+   u8 mcr, msr;
+
+   /* force get current MSR changed state */
+   f81232_read_msr(port);
+
+   mutex_lock(&port_priv->lock);
+   mcr = port_priv->modem_control;
+   msr = port_priv->modem_status;
+   mutex_unlock(&port_priv->lock);
+
+   r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) |
+   (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) |
+   (msr & UART_MSR_CTS ? TIOCM_CTS : 0) |
+   (msr & UART_MSR_DCD ? TIOCM_CAR : 0) |
+   (msr & UART_MSR_RI ? TIOCM_RI : 0) |
+   (msr & UART_MSR_DSR ? TIOCM_DSR : 0);
+
+   return r;
 }
 
 static int f81232_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   struct usb_serial_port *port = tty->driver_data;
+
+   return f81232_set_mctrl(port, set, clear);
 }
 
 static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -385,24 +446,22 @@ static void f81232_close(struct usb_serial_port *port)
 
 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 {
-   struct f81232_private *priv = usb_get_serial_port_data(port);
-   

[PATCH V7 01/11] USB: f81232: rename private struct member name

2015-02-24 Thread Peter Hung
Change private struct member name from line_status to modem_status.
It will store MSR for some functions used

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c5dc233..669a2f2 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,7 +47,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 struct f81232_private {
spinlock_t lock;
u8 line_control;
-   u8 line_status;
+   u8 modem_status;
 };
 
 static void f81232_update_line_status(struct usb_serial_port *port,
@@ -113,8 +113,8 @@ static void f81232_process_read_urb(struct urb *urb)
 
/* update line status */
spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->line_status;
-   priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+   line_status = priv->modem_status;
+   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
 
if (!urb->actual_length)
@@ -241,7 +241,7 @@ static void f81232_dtr_rts(struct usb_serial_port *port, 
int on)
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   if (priv->line_status & UART_DCD)
+   if (priv->modem_status & UART_DCD)
return 1;
return 0;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 02/11] USB: f81232: add preparatory functions

2015-02-24 Thread Peter Hung
We add f81232_get_register()/f81232_set_register() and necessary defines
for future patch with communication with F81232 USB control endpoint.

Because of this is a preparatory patch, there are unused function warning
with compiling. The functions will used with following patches.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 79 +
 1 file changed, 79 insertions(+)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 669a2f2..1f29b95 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -30,6 +30,11 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* USB Control EP parameter */
+#define F81232_REGISTER_REQUEST0xA0
+#define F81232_GET_REGISTER0xc0
+#define F81232_SET_REGISTER0x40
+
 #define CONTROL_DTR0x01
 #define CONTROL_RTS0x02
 
@@ -50,6 +55,80 @@ struct f81232_private {
u8 modem_status;
 };
 
+static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *data)
+{
+   int status;
+   u8 *tmp;
+   struct usb_device *dev = port->serial->dev;
+
+   if (!data)
+   return -EFAULT;
+
+   tmp = kmalloc(sizeof(u8), GFP_KERNEL);
+   if (!tmp)
+   return -ENOMEM;
+
+   status = usb_control_msg(dev,
+   usb_rcvctrlpipe(dev, 0),
+   F81232_REGISTER_REQUEST,
+   F81232_GET_REGISTER,
+   reg,
+   0,
+   tmp,
+   sizeof(u8),
+   USB_CTRL_GET_TIMEOUT);
+   if (status <= 0) {
+   /* show something with failed */
+   dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
+
+   if (status == 0)
+   status = -EIO;
+   else
+   status = usb_translate_errors(status);
+   } else {
+   status = 0; /* on success */
+   memcpy((void*) data, (void*) tmp, sizeof(u8));
+   }
+
+   kfree(tmp);
+   return status;
+}
+
+static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 data)
+{
+   int status;
+   u8 *tmp;
+   struct usb_device *dev = port->serial->dev;
+
+   tmp = kmalloc(sizeof(u8), GFP_KERNEL);
+   if (!tmp)
+   return -ENOMEM;
+
+   memcpy((void*) tmp, (void*) &data, sizeof(u8));
+
+   status = usb_control_msg(dev,
+   usb_sndctrlpipe(dev, 0),
+   F81232_REGISTER_REQUEST,
+   F81232_SET_REGISTER,
+   reg,
+   0,
+   tmp,
+   sizeof(u8),
+   USB_CTRL_SET_TIMEOUT);
+   if (status <= 0) {
+   /* show something with failed */
+   dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
+
+   if (status == 0)
+   status = -EIO;
+   else
+   status = usb_translate_errors(status);
+   } else
+   status = 0; /* on success */
+
+   kfree(tmp);
+   return status;
+}
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
  unsigned int actual_length)
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 03/11] USB: f81232: implement RX bulk-in EP

2015-02-24 Thread Peter Hung
The F81232 bulk-in is RX data + LSR channel, data format is
[LSR+Data][LSR+Data]. , We had implemented in f81232_process_read_urb().

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 69 +++--
 1 file changed, 36 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 1f29b95..419e2d6 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 
 static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1934, 0x0706) },
@@ -183,44 +184,46 @@ exit:
 static void f81232_process_read_urb(struct urb *urb)
 {
struct usb_serial_port *port = urb->context;
-   struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
-   char tty_flag = TTY_NORMAL;
-   unsigned long flags;
-   u8 line_status;
+   char tty_flag;
int i;
+   u8 lsr;
 
-   /* update line status */
-   spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->modem_status;
-   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
-   spin_unlock_irqrestore(&priv->lock, flags);
-
-   if (!urb->actual_length)
+   if (urb->actual_length < 2)
return;
 
-   /* break takes precedence over parity, */
-   /* which takes precedence over framing errors */
-   if (line_status & UART_BREAK_ERROR)
-   tty_flag = TTY_BREAK;
-   else if (line_status & UART_PARITY_ERROR)
-   tty_flag = TTY_PARITY;
-   else if (line_status & UART_FRAME_ERROR)
-   tty_flag = TTY_FRAME;
-   dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
-
-   /* overrun is special, not associated with a char */
-   if (line_status & UART_OVERRUN_ERROR)
-   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
-   if (port->port.console && port->sysrq) {
-   for (i = 0; i < urb->actual_length; ++i)
-   if (!usb_serial_handle_sysrq_char(port, data[i]))
-   tty_insert_flip_char(&port->port, data[i],
-   tty_flag);
-   } else {
-   tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
-   urb->actual_length);
+   /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
+
+   for (i = 0; i < urb->actual_length; i += 2) {
+   tty_flag = TTY_NORMAL;
+   lsr = data[i + 0];
+
+   if (lsr & UART_LSR_BRK_ERROR_BITS) {
+   if (lsr & UART_LSR_BI) {
+   tty_flag = TTY_BREAK;
+   port->icount.brk++;
+   usb_serial_handle_break(port);
+   } else if (lsr & UART_LSR_PE) {
+   tty_flag = TTY_PARITY;
+   port->icount.parity++;
+   } else if (lsr & UART_LSR_FE) {
+   tty_flag = TTY_FRAME;
+   port->icount.frame++;
+   }
+
+   if (lsr & UART_LSR_OE) {
+   port->icount.overrun++;
+   tty_insert_flip_char(&port->port, 0,
+   TTY_OVERRUN);
+   }
+   }
+
+   if (port->port.console && port->sysrq) {
+   if (usb_serial_handle_sysrq_char(port, data[i + 1]))
+   continue;
+   }
+
+   tty_insert_flip_char(&port->port, data[i + 1], tty_flag);
}
 
tty_flip_buffer_push(&port->port);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 05/11] USB: f81232: implement read IIR/MSR with endpoint

2015-02-24 Thread Peter Hung
The interrupt endpoint will report current IIR. If we got IIR with MSR changed
, We will do read MSR with interrupt_work worker to do f81232_read_msr()
function.

We also confirmd MSR strange delta value is not locking-issue. The issue
is set MCR & get MSR before IIR notice with MSR changed (Loopback only).

When we use RS232 loopback, assume doing RTS change will cause
CTS change, DTR change will cause DCD/DSR change too.

Sometimes we got 7~4 bits of MSR changed but the 3~0 bits of
MSR(delta) maybe not changed when set & get MCR rapidly.

So we add more check not only UART_MSR_ANY_DELTA but also with
comparing DCD/RI/DSR/CTS change with old value. Because of the state
bit is always correct, we direct save msr when read.

The following step to reproduce this problem with while loop step 1~4:
1. ioctl(fd, TIOCMSET, &data) to set RTS or DTR
2. ioctl(fd, TIOCMGET, &data) to read CTS or DCD/DSR state
3. ioctl(fd, TIOCMSET, &data) to unset RTS or DTR
4. ioctl(fd, TIOCMGET, &data) to read CTS or DCD/DSR state

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 106 
 1 file changed, 98 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index bf072fe..339be30 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -36,6 +36,9 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_GET_REGISTER0xc0
 #define F81232_SET_REGISTER0x40
 
+#define SERIAL_BASE_ADDRESS0x0120
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
+
 #define CONTROL_DTR0x01
 #define CONTROL_RTS0x02
 
@@ -54,6 +57,8 @@ struct f81232_private {
struct mutex lock;
u8 line_control;
u8 modem_status;
+   struct work_struct interrupt_work;
+   struct usb_serial_port *port;
 };
 
 static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *data)
@@ -130,17 +135,92 @@ static int f81232_set_register(struct usb_serial_port 
*port, u16 reg, u8 data)
kfree(tmp);
return status;
 }
+
+static void f81232_read_msr(struct usb_serial_port *port)
+{
+   int status;
+   u8 current_msr, prev_msr;
+   u8 msr_mask = ~UART_MSR_ANY_DELTA;
+   u8 msr_changed_bit;
+   struct tty_struct *tty;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   status = f81232_get_register(port, MODEM_STATUS_REGISTER,
+   ¤t_msr);
+   if (status) {
+   dev_err(&port->dev, "%s fail, status: %d\n", __func__, status);
+   return;
+   }
+
+   /*
+   *  The 7~4 bits of MSR will change but the 3~0 bits of MSR(delta)
+   *  maybe not change when set MCR & get MSR rapidly.
+   *
+   *  So we add more check with comparing DCD/RI/DSR/CTS
+   *  change. and direct save msr when read.
+   */
+
+   mutex_lock(&priv->lock);
+   prev_msr = priv->modem_status;
+   priv->modem_status = current_msr;
+   mutex_unlock(&priv->lock);
+
+   if (!(current_msr & UART_MSR_ANY_DELTA) &&
+   !((prev_msr ^ current_msr) & msr_mask))
+   return;
+
+   /* find checked delta bits set */
+   msr_changed_bit =
+   (current_msr & UART_MSR_ANY_DELTA) << 4;
+
+   /* append with not delta but changed bits */
+   msr_changed_bit |= (prev_msr ^ current_msr) & msr_mask;
+
+   if (msr_changed_bit & UART_MSR_CTS)
+   port->icount.cts++;
+   if (msr_changed_bit & UART_MSR_DSR)
+   port->icount.dsr++;
+   if (msr_changed_bit & UART_MSR_RI)
+   port->icount.rng++;
+   if (msr_changed_bit & UART_MSR_DCD) {
+
+   port->icount.dcd++;
+   tty = tty_port_tty_get(&port->port);
+   if (tty) {
+
+   usb_serial_handle_dcd_change(port, tty,
+   current_msr & UART_MSR_DCD);
+
+   tty_kref_put(tty);
+   }
+   }
+
+   wake_up_interruptible(&port->port.delta_msr_wait);
+}
+
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
- unsigned int actual_length)
+ size_t actual_length)
 {
-   /*
-* FIXME: Update port->icount, and call
-*
-*  wake_up_interruptible(&port->port.delta_msr_wait);
-*
-*on MSR changes.
-*/
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (!actual_length)
+   return;
+
+   switch (data[0] & 0x07) {
+   case 0x00: /* msr change */
+   dev_dbg(&port->dev, "I

[PATCH V7 07/11] USB: f81232: implement port_enable function

2015-02-24 Thread Peter Hung
We put FCR/IER initial step to f81232_port_enable(). When port is open,
it set MSR interrupt on. Otherwise set it off.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 21f606f..f5c9060 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -37,6 +37,8 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
@@ -367,6 +369,33 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 */
 }
 
+static int f81232_port_enable(struct usb_serial_port *port, int enable)
+{
+   u8 data = 0;
+   int status;
+
+   /* fifo on, trigger8, clear TX/RX*/
+   data = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR
+   | UART_FCR_CLEAR_XMIT;
+
+   status = f81232_set_register(port, FIFO_CONTROL_REGISTER, data);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set FCR: %d\n", __func__, 
status);
+   return status;
+   }
+
+   /* MSR Interrupt only, LSR will read from Bulk-in odd byte */
+   data = enable ? UART_IER_MSI : 0;
+
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, data);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set IER: %d\n", __func__, 
status);
+   return status;
+   }
+
+   return 0;
+}
+
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -418,6 +447,12 @@ static int f81232_open(struct tty_struct *tty, struct 
usb_serial_port *port)
 {
int result;
 
+   result = f81232_port_enable(port, 1);
+   if (result) {
+   dev_err(&port->dev, "%s - init fail: %d\n", __func__, result);
+   return result;
+   }
+
/* Setup termios */
if (tty)
f81232_set_termios(tty, port, NULL);
@@ -440,6 +475,10 @@ static int f81232_open(struct tty_struct *tty, struct 
usb_serial_port *port)
 
 static void f81232_close(struct usb_serial_port *port)
 {
+   int result = f81232_port_enable(port, 0);
+   if (result)
+   dev_err(&port->dev, "%s - init fail: %d\n", __func__, result);
+
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 08/11] USB: f81232: implement set_termios()

2015-02-24 Thread Peter Hung
The original driver had do not any h/w change in driver.
This patch implements with configure H/W for
baud/parity/word length/stop bits functional in f81232_set_termios().

This patch also implement DTR/RTS control when baudrate B0.
We drop DTR/RTS when B0, otherwise enable it.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 106 ++--
 1 file changed, 102 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index f5c9060..0c96b9a 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -31,14 +31,19 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* Maximum baudrate for F81232 */
+#define F81232_MAX_BAUDRATE115200
+
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST0xA0
 #define F81232_GET_REGISTER0xc0
 #define F81232_SET_REGISTER0x40
 
 #define SERIAL_BASE_ADDRESS0x0120
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
 #define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
 #define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
@@ -64,6 +69,14 @@ struct f81232_private {
struct usb_serial_port *port;
 };
 
+static int calc_baud_divisor(u32 baudrate)
+{
+   if (!baudrate)
+   return 0;
+   else
+   return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate);
+}
+
 static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *data)
 {
int status;
@@ -369,6 +382,52 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 */
 }
 
+static void f81232_set_baudrate(struct usb_serial_port *port, int baudrate)
+{
+   u8 divisor, lcr;
+   int status = 0;
+
+   if (!baudrate)
+   return;
+
+   divisor = calc_baud_divisor(baudrate);
+
+   status = f81232_get_register(port, LINE_CONTROL_REGISTER,
+&lcr); /* get LCR */
+   if (status) {
+   dev_err(&port->dev, "%s failed to get LCR: %d\n",
+   __func__, status);
+   }
+
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+lcr | UART_LCR_DLAB); /* Enable DLAB */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set DLAB: %d\n",
+   __func__, status);
+   }
+
+   status = f81232_set_register(port, RECEIVE_BUFFER_REGISTER,
+divisor & 0x00ff); /* low */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set baudrate MSB: %d\n",
+   __func__, status);
+   }
+
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER,
+(divisor & 0xff00) >> 8); /* high */
+   if (status) {
+   dev_err(&port->dev, "%s failed to set baudrate LSB: %d\n",
+   __func__, status);
+   }
+
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+   lcr & ~UART_LCR_DLAB);
+   if (status) {
+   dev_err(&port->dev, "%s failed to set DLAB: %d\n",
+   __func__, status);
+   }
+}
+
 static int f81232_port_enable(struct usb_serial_port *port, int enable)
 {
u8 data = 0;
@@ -399,15 +458,54 @@ static int f81232_port_enable(struct usb_serial_port 
*port, int enable)
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
 {
-   /* FIXME - Stubbed out for now */
+   u8 new_lcr = 0;
+   int status = 0;
+
 
/* Don't change anything if nothing has changed */
if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
 
-   /* Do the real work here... */
-   if (old_termios)
-   tty_termios_copy_hw(&tty->termios, old_termios);
+   if (C_BAUD(tty) == B0)
+   f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
+   else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+   f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0);
+
+   f81232_set_baudrate(port, tty_get_baud_rate(tty));
+
+   if (C_PARENB(tty)) {
+   new_lcr |= UART_LCR_PARITY;
+
+   if (!C_PARODD(tty))
+   new_lcr |= UART_LCR_EPAR;
+
+   if (C_CMSPAR(tty))
+   new_lcr |= UART_LCR_SPAR;
+   }
+
+   if (C_CSTOPB(tty))
+   new_lcr |= UART_LCR_STOP;
+
+   switch (C_CSIZE(tty)) {
+   case CS5:
+   n

[PATCH V7 10/11] USB: f81232: cleanup non-used define

2015-02-24 Thread Peter Hung
We remove non-used define in this patch to avoid wrong usage.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 14 --
 1 file changed, 14 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 3b0da70..ee9a2a2 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,20 +47,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
-#define CONTROL_DTR0x01
-#define CONTROL_RTS0x02
-
-#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
-
 struct f81232_private {
struct mutex lock;
u8 modem_control;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 09/11] USB: f81232: clarify f81232_ioctl() and fix

2015-02-24 Thread Peter Hung
We extract TIOCGSERIAL section in f81232_ioctl() to f81232_get_serial_info()
to make it clarify.

Also we fix device type from 16654 to 16550A, and set it's baud_base
to 115200 (1.8432MHz/16).

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 30 +++---
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 0c96b9a..3b0da70 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -603,24 +603,32 @@ static int f81232_carrier_raised(struct usb_serial_port 
*port)
return 0;
 }
 
+static int f81232_get_serial_info(struct usb_serial_port *port,
+   unsigned long arg)
+{
+   struct serial_struct ser;
+
+   memset(&ser, 0, sizeof(ser));
+
+   ser.type = PORT_16550A;
+   ser.line = port->minor;
+   ser.port = port->port_number;
+   ser.baud_base = 115200;
+
+   if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
+   return -EFAULT;
+
+   return 0;
+}
+
 static int f81232_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
 {
-   struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
 
switch (cmd) {
case TIOCGSERIAL:
-   memset(&ser, 0, sizeof ser);
-   ser.type = PORT_16654;
-   ser.line = port->minor;
-   ser.port = port->port_number;
-   ser.baud_base = 460800;
-
-   if (copy_to_user((void __user *)arg, &ser, sizeof ser))
-   return -EFAULT;
-
-   return 0;
+   return f81232_get_serial_info(port, arg);
default:
break;
}
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V7 11/11] USB: f81232: modify/add author

2015-02-24 Thread Peter Hung
Add me to co-author and fix no '>' in greg kh's email

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index ee9a2a2..23f0a17 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -691,5 +691,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
-MODULE_AUTHOR("Greg Kroah-Hartman ");
+MODULE_AUTHOR("Peter Hong ");
 MODULE_LICENSE("GPL v2");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V6 08/10] USB: f81232: fix read MSR strange value

2015-02-23 Thread Peter Hung

Hello,

Johan Hovold 於 2015/2/17 下午 05:51 寫道:


So we add more check not only UART_MSR_ANY_DELTA but also with
comparing DCD/RI/DSR/CTS change with old value. Due to the state
bit is always correct, we direct save msr when read.

The following step to reproduce this problem with while loop step 1~4:
1. ioctl(fd, TIOCMSET, &data) to set RTS or DTR
2. ioctl(fd, TIOCMGET, &data) to read CTS or DCD/DSR state
3. ioctl(fd, TIOCMSET, &data) to unset RTS or DTR
4. ioctl(fd, TIOCMGET, &data) to read CTS or DCD/DSR state


Without having looked at this very closely; are you sure this is a
hardware issue and not related to the locking issues I pointed at in my
comments to tiocmset?

Johan



Thank for your review.

I'll apply all suggestions to next v7 patch.

--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V6 03/10] USB: f81232: implement RX bulk-in ep

2015-02-16 Thread Peter Hung

Hello,

Greg KH 於 2015/2/17 上午 03:41 寫道:


+   if (unlikely(data[i+0] & UART_LSR_BRK_ERROR_BITS)) {


Never use unlikely() unless you can prove that it actually matters if
you use it.  Hint, it's almost impossible to prove, so don't use it, the
compiler and processor look-ahead is almost smarter than we are.


Thanks for your hint. I'll remove it with next patch.

--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 03/10] USB: f81232: implement RX bulk-in ep

2015-02-16 Thread Peter Hung
The F81232 bulk-in is RX data + LSR channel, data format is
[LSR+Data][LSR+Data]. , We had reimplemented in this patch.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 68 +++--
 1 file changed, 35 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index ec4609d..9ea498a 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -185,44 +185,46 @@ exit:
 static void f81232_process_read_urb(struct urb *urb)
 {
struct usb_serial_port *port = urb->context;
-   struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
-   char tty_flag = TTY_NORMAL;
-   unsigned long flags;
-   u8 line_status;
+   char tty_flag;
int i;
 
-   /* update line status */
-   spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->modem_status;
-   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
-   spin_unlock_irqrestore(&priv->lock, flags);
-
-   if (!urb->actual_length)
+   if (urb->actual_length < 2)
return;
 
-   /* break takes precedence over parity, */
-   /* which takes precedence over framing errors */
-   if (line_status & UART_BREAK_ERROR)
-   tty_flag = TTY_BREAK;
-   else if (line_status & UART_PARITY_ERROR)
-   tty_flag = TTY_PARITY;
-   else if (line_status & UART_FRAME_ERROR)
-   tty_flag = TTY_FRAME;
-   dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
-
-   /* overrun is special, not associated with a char */
-   if (line_status & UART_OVERRUN_ERROR)
-   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
-   if (port->port.console && port->sysrq) {
-   for (i = 0; i < urb->actual_length; ++i)
-   if (!usb_serial_handle_sysrq_char(port, data[i]))
-   tty_insert_flip_char(&port->port, data[i],
-   tty_flag);
-   } else {
-   tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
-   urb->actual_length);
+   /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
+
+   for (i = 0 ; i < urb->actual_length ; i += 2) {
+   tty_flag = TTY_NORMAL;
+
+   if (unlikely(data[i+0] & UART_LSR_BRK_ERROR_BITS)) {
+   if (data[i+0] & UART_LSR_BI) {
+   tty_flag = TTY_BREAK;
+   port->icount.brk++;
+   usb_serial_handle_break(port);
+   } else if (data[i+0] & UART_LSR_PE) {
+   tty_flag = TTY_PARITY;
+   port->icount.parity++;
+   } else if (data[i+0] & UART_LSR_FE) {
+   tty_flag = TTY_FRAME;
+   port->icount.frame++;
+   }
+
+   if (data[0] & UART_LSR_OE) {
+   port->icount.overrun++;
+   tty_insert_flip_char(&port->port, 0,
+   TTY_OVERRUN);
+   }
+   }
+
+   if (port->port.console && port->sysrq) {
+   if (!usb_serial_handle_sysrq_char(port, data[i+1]))
+   tty_insert_flip_char(&port->port, data[i+1],
+   tty_flag);
+   } else {
+   tty_insert_flip_string_fixed_flag(&port->port,
+   &data[i+1], tty_flag, 1);
+   }
}
 
tty_flip_buffer_push(&port->port);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 01/10] USB: f81232: rename private struct member name

2015-02-16 Thread Peter Hung
Change private struct member name from line_status to modem_status.
It will store MSR for some functions used

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c5dc233..669a2f2 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,7 +47,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 struct f81232_private {
spinlock_t lock;
u8 line_control;
-   u8 line_status;
+   u8 modem_status;
 };
 
 static void f81232_update_line_status(struct usb_serial_port *port,
@@ -113,8 +113,8 @@ static void f81232_process_read_urb(struct urb *urb)
 
/* update line status */
spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->line_status;
-   priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+   line_status = priv->modem_status;
+   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
 
if (!urb->actual_length)
@@ -241,7 +241,7 @@ static void f81232_dtr_rts(struct usb_serial_port *port, 
int on)
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   if (priv->line_status & UART_DCD)
+   if (priv->modem_status & UART_DCD)
return 1;
return 0;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 00/10] USB: f81232: V6 patches

2015-02-16 Thread Peter Hung
This series patch V6 is improvement from V5&V4 as following:

1. transform all function not to use private data as parameter, using
   usb_serial_port instead.

2. process_read_urb() add process of Break/FrameError/ParityError/OE.
   (patch: 03/10)

3. fix calc_baud_divisor() will cause divide by zero with B0. (patch: 04/10)

4. Some init step we extract it from set_termios() to f81232_port_init()
   and run it when open port only. (patch: 04/10)

5. We'll force re-read msr in tiocmget() because the IIR with MSR change
   maybe delay received. (patch: 05/10)

6. fix MSR status bits changed but delta bits is 0 will cause read serial port
   malfunctional with update port status. (patch: 08/10)

7. Add MSR change statistic when MSR has been read. (patch: 09/10)   
   
8. clarify a lot of code about Johan suggested.

Logs:

1. We had add dev_err() in set/get register function. Also add dev_err()
   in some function is to help us easily point out error position, so we
   still decide to remain it.

Thanks for reading.

Peter Hung (10):
  USB: f81232: rename private struct member name
  USB: f81232: implement read IIR/MSR with endpoint
  USB: f81232: implement RX bulk-in ep
  USB: f81232: implement set_termios
  USB: f81232: implement MCR/MSR function
  USB: f81232: clarify f81232_ioctl and fix
  USB: f81232: fix error in f81232_carrier_raised()
  USB: f81232: fix read MSR strange value
  USB: f81232: implement delta change for MSR count
  USB: f81232: modify/add author

 drivers/usb/serial/f81232.c | 495 +++-
 1 file changed, 399 insertions(+), 96 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 02/10] USB: f81232: implement read IIR/MSR with endpoint

2015-02-16 Thread Peter Hung
The interrupt Endpoint will report current IIR. If we got IIR with MSR Changed
, We will do read MSR with interrupt_work worker to do f81232_read_msr() func.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 109 
 1 file changed, 100 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 669a2f2..ec4609d 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 
 static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1934, 0x0706) },
@@ -30,6 +31,13 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* USB Control EP parameter */
+#define F81232_REGISTER_REQUEST 0xA0
+#define F81232_GET_REGISTER 0xc0
+
+#define SERIAL_BASE_ADDRESS   0x0120
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
+
 #define CONTROL_DTR0x01
 #define CONTROL_RTS0x02
 
@@ -48,19 +56,92 @@ struct f81232_private {
spinlock_t lock;
u8 line_control;
u8 modem_status;
+
+   struct work_struct interrupt_work;
+   struct usb_serial_port *port;
 };
 
-static void f81232_update_line_status(struct usb_serial_port *port,
+static int f81232_get_register(struct usb_serial_port *port,
+ u16 reg, u8 *data)
+{
+   int status;
+   struct usb_device *dev = port->serial->dev;
+
+   status = usb_control_msg(dev,
+usb_rcvctrlpipe(dev, 0),
+F81232_REGISTER_REQUEST,
+F81232_GET_REGISTER,
+reg,
+0,
+data,
+sizeof(*data),
+USB_CTRL_GET_TIMEOUT);
+   if (status < 0)
+   dev_err(&port->dev, "%s status: %d\n", __func__, status);
+
+   return status;
+}
+
+static void f81232_read_msr(struct usb_serial_port *port)
+{
+   int status;
+   unsigned long flags;
+   u8 current_msr;
+   struct tty_struct *tty;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   status = f81232_get_register(port, MODEM_STATUS_REGISTER,
+   ¤t_msr);
+   if (status < 0) {
+   /* Retain the error even reported in f81232_get_register()
+to make debug easily :D */
+   dev_err(&port->dev, "%s fail, status: %d\n", __func__, status);
+   return;
+   }
+
+   if (!(current_msr & UART_MSR_ANY_DELTA))
+   return;
+
+   tty = tty_port_tty_get(&port->port);
+   if (tty) {
+   if (current_msr & UART_MSR_DDCD) {
+   usb_serial_handle_dcd_change(port, tty,
+   current_msr & UART_MSR_DCD);
+   }
+
+   tty_kref_put(tty);
+   }
+
+   spin_lock_irqsave(&priv->lock, flags);
+   priv->modem_status = current_msr;
+   spin_unlock_irqrestore(&priv->lock, flags);
+
+   wake_up_interruptible(&port->port.delta_msr_wait);
+}
+
+static void f81232_update_modem_status(struct usb_serial_port *port,
  unsigned char *data,
  unsigned int actual_length)
 {
-   /*
-* FIXME: Update port->icount, and call
-*
-*  wake_up_interruptible(&port->port.delta_msr_wait);
-*
-*on MSR changes.
-*/
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (!actual_length)
+   return;
+
+   switch (data[0] & 0x07) {
+   case 0x00: /* msr change */
+   dev_dbg(&port->dev, "IIR: MSR Change: %x\n", data[0]);
+   schedule_work(&priv->interrupt_work);
+   break;
+   case 0x02: /* tx-empty */
+   break;
+   case 0x04: /* rx data available */
+   break;
+   case 0x06: /* lsr change */
+   /* we can forget it. the LSR will read from bulk-in */
+   dev_dbg(&port->dev, "IIR: LSR Change: %x\n", data[0]);
+   break;
+   }
 }
 
 static void f81232_read_int_callback(struct urb *urb)
@@ -91,7 +172,7 @@ static void f81232_read_int_callback(struct urb *urb)
usb_serial_debug_data(&port->dev, __func__,
  urb->actual_length, urb->transfer_buffer);
 
-   f81232_update_line_status(port, data, actual_length);
+   f81232_update_modem_status(port, data, actual_length);
 
 exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -270,6 +351,14 @@ static int f81232_ioctl(struct tty_struct *tty,
retur

[PATCH V6 10/10] USB: f81232: modify/add author

2015-02-16 Thread Peter Hung
Add me to co-author and fix no '>' in greg kh's email

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 5134a19..5e35859 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -632,5 +632,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
-MODULE_AUTHOR("Greg Kroah-Hartman ");
+MODULE_AUTHOR("Peter Hong ");
 MODULE_LICENSE("GPL v2");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 04/10] USB: f81232: implement set_termios

2015-02-16 Thread Peter Hung
The original driver had do not any h/w change in driver.
This patch implements with configure H/W for
baud/parity/word length/stop bits functional.

Some init step extract to f81232_port_init(), called once with open().
And refine baudrate setting to f81232_set_baudrate()

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 145 +---
 1 file changed, 138 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 9ea498a..06d1eb0 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -31,11 +31,19 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* Maximum baudrate for F81232 */
+#define F81232_MAX_BAUDRATE 115200L
+
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST 0xA0
 #define F81232_GET_REGISTER 0xc0
+#define F81232_SET_REGISTER 0x40
 
 #define SERIAL_BASE_ADDRESS   0x0120
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
 #define CONTROL_DTR0x01
@@ -61,6 +69,14 @@ struct f81232_private {
struct usb_serial_port *port;
 };
 
+static int calc_baud_divisor(u32 baudrate)
+{
+   if (!baudrate)
+   return 0;
+   else
+   return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate);
+}
+
 static int f81232_get_register(struct usb_serial_port *port,
  u16 reg, u8 *data)
 {
@@ -82,6 +98,27 @@ static int f81232_get_register(struct usb_serial_port *port,
return status;
 }
 
+static int f81232_set_register(struct usb_serial_port *port,
+ u16 reg, u8 data)
+{
+   int status;
+   struct usb_device *dev = port->serial->dev;
+
+   status = usb_control_msg(dev,
+   usb_sndctrlpipe(dev, 0),
+   F81232_REGISTER_REQUEST,
+   F81232_SET_REGISTER,
+   reg,
+   0,
+   &data,
+   sizeof(data),
+   USB_CTRL_SET_TIMEOUT);
+   if (status < 0)
+   dev_err(&port->dev, "%s status: %d\n", __func__, status);
+
+   return status;
+}
+
 static void f81232_read_msr(struct usb_serial_port *port)
 {
int status;
@@ -247,18 +284,106 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 */
 }
 
+static void f81232_set_baudrate(struct usb_serial_port *port, int baudrate)
+{
+   u8 divisor;
+   int status = 0;
+
+   divisor = calc_baud_divisor(baudrate);
+
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+UART_LCR_DLAB); /* DLAB */
+   if (status < 0) {
+   dev_err(&port->dev, "%s status: %d line:%d\n",
+   __func__, status, __LINE__);
+   }
+
+   status = f81232_set_register(port, RECEIVE_BUFFER_REGISTER,
+divisor & 0x00ff); /* low */
+   if (status < 0) {
+   dev_err(&port->dev, "%s status: %d line:%d\n",
+   __func__, status, __LINE__);
+   }
+
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER,
+(divisor & 0xff00) >> 8); /* high */
+   if (status < 0) {
+   dev_err(&port->dev, "%s status: %d line:%d\n", __func__,
+   status, __LINE__);
+   }
+
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER, 0x00);
+   if (status < 0) {
+   dev_err(&port->dev, "%s status: %d line:%d\n", __func__,
+   status, __LINE__);
+   }
+}
+
+static int f81232_port_init(struct usb_serial_port *port)
+{
+   u8 data;
+   int status = 0;
+
+   /* fifo on, trigger8, clear TX/RX*/
+   data = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR
+   | UART_FCR_CLEAR_XMIT;
+
+   status |= f81232_set_register(port, FIFO_CONTROL_REGISTER, data);
+
+   /* MSR Interrupt only, LSR will read from Bulk-in odd byte */
+   data = UART_IER_MSI;
+
+   /* IER */
+   status |= f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, data);
+   if (status < 0) {
+   dev_err(&port->dev, "%s set error: %d\n", __func__, status);
+   return status;
+   }
+
+   return 0;
+}
+
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios

[PATCH V6 09/10] USB: f81232: implement delta change for MSR count

2015-02-16 Thread Peter Hung
We implement delta change for MSR counting. This patch is referenced
from ftdi_sio.c

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 27 ++-
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 94c05d7..5134a19 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -112,6 +112,7 @@ static void f81232_read_msr(struct usb_serial_port *port)
unsigned long flags;
u8 current_msr, prev_msr;
u8 msr_mask = ~UART_MSR_ANY_DELTA;
+   u8 msr_changed_bit;
struct tty_struct *tty;
struct f81232_private *priv = usb_get_serial_port_data(port);
 
@@ -141,14 +142,30 @@ static void f81232_read_msr(struct usb_serial_port *port)
!((prev_msr ^ current_msr) & msr_mask))
return;
 
-   tty = tty_port_tty_get(&port->port);
-   if (tty) {
-   if (current_msr & UART_MSR_DDCD) {
+   /* find checked delta bits set */
+   msr_changed_bit =
+   (current_msr & UART_MSR_ANY_DELTA) << 4;
+
+   /* append with not delta but changed bits */
+   msr_changed_bit |= (prev_msr ^ current_msr) & msr_mask;
+
+   if (msr_changed_bit & UART_MSR_CTS)
+   port->icount.cts++;
+   if (msr_changed_bit & UART_MSR_DSR)
+   port->icount.dsr++;
+   if (msr_changed_bit & UART_MSR_RI)
+   port->icount.rng++;
+   if (msr_changed_bit & UART_MSR_DCD) {
+
+   port->icount.dcd++;
+   tty = tty_port_tty_get(&port->port);
+   if (tty) {
+
usb_serial_handle_dcd_change(port, tty,
current_msr & UART_MSR_DCD);
-   }
 
-   tty_kref_put(tty);
+   tty_kref_put(tty);
+   }
}
 
wake_up_interruptible(&port->port.delta_msr_wait);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 05/10] USB: f81232: implement MCR/MSR function

2015-02-16 Thread Peter Hung
This patch implement relative MCR/MSR function, such like
tiocmget()/tiocmset()/dtr_rts().

The f81232_set_mctrl() replace set_control_lines() to do MCR control
so we clean-up the set_control_lines() function.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 98 +++--
 1 file changed, 77 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 06d1eb0..e1cdf42 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -44,6 +44,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
 #define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
 #define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
 #define CONTROL_DTR0x01
@@ -156,6 +157,50 @@ static void f81232_read_msr(struct usb_serial_port *port)
wake_up_interruptible(&port->port.delta_msr_wait);
 }
 
+static int f81232_set_mctrl(struct usb_serial_port *port,
+  unsigned int set, unsigned int clear)
+{
+   u8 urb_value;
+   int status;
+   unsigned long flags;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0)
+   return 0;   /* no change */
+
+   /* 'set' takes precedence over 'clear' */
+   clear &= ~set;
+
+   /* force enable interrupt with OUT2 */
+   urb_value = UART_MCR_OUT2 | priv->line_control;
+
+   if (clear & TIOCM_DTR)
+   urb_value &= ~UART_MCR_DTR;
+
+   if (clear & TIOCM_RTS)
+   urb_value &= ~UART_MCR_RTS;
+
+   if (set & TIOCM_DTR)
+   urb_value |= UART_MCR_DTR;
+
+   if (set & TIOCM_RTS)
+   urb_value |= UART_MCR_RTS;
+
+   dev_dbg(&port->dev, "%s new:%02x old:%02x\n", __func__,
+   urb_value, priv->line_control);
+
+   status = f81232_set_register(port, MODEM_CONTROL_REGISTER, urb_value);
+   if (status < 0) {
+   dev_err(&port->dev, "%s set MCR status < 0\n", __func__);
+   } else {
+   spin_lock_irqsave(&priv->lock, flags);
+   priv->line_control = urb_value;
+   spin_unlock_irqrestore(&priv->lock, flags);
+   }
+
+   return status;
+}
+
 static void f81232_update_modem_status(struct usb_serial_port *port,
  unsigned char *data,
  unsigned int actual_length)
@@ -267,12 +312,6 @@ static void f81232_process_read_urb(struct urb *urb)
tty_flip_buffer_push(&port->port);
 }
 
-static int set_control_lines(struct usb_device *dev, u8 value)
-{
-   /* FIXME - Stubbed out for now */
-   return 0;
-}
-
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
/* FIXME - Stubbed out for now */
@@ -388,15 +427,41 @@ static void f81232_set_termios(struct tty_struct *tty,
 
 static int f81232_tiocmget(struct tty_struct *tty)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int r;
+   struct usb_serial_port *port = tty->driver_data;
+   struct f81232_private *port_priv = usb_get_serial_port_data(port);
+   unsigned long flags;
+   u8 mcr, msr;
+
+   /* force get current MSR changed state */
+   f81232_read_msr(port);
+
+   spin_lock_irqsave(&port_priv->lock, flags);
+   mcr = port_priv->line_control;
+   msr = port_priv->modem_status;
+   spin_unlock_irqrestore(&port_priv->lock, flags);
+
+   r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) |
+   (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) |
+   (msr & UART_MSR_CTS ? TIOCM_CTS : 0) |
+   (msr & UART_MSR_DCD ? TIOCM_CAR : 0) |
+   (msr & UART_MSR_RI ? TIOCM_RI : 0) |
+   (msr & UART_MSR_DSR ? TIOCM_DSR : 0);
+
+   return r;
 }
 
 static int f81232_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int status;
+   struct usb_serial_port *port = tty->driver_data;
+
+   status = f81232_set_mctrl(port, set, clear);
+   if (status < 0)
+   return usb_translate_errors(status);
+   else
+   return 0;
 }
 
 static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -437,19 +502,10 @@ static void f81232_close(struct usb_serial_port *port)
 
 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 {
-   struct f81232_private *priv = usb_get_serial_port_data(port);

[PATCH V6 06/10] USB: f81232: clarify f81232_ioctl and fix

2015-02-16 Thread Peter Hung
We extract TIOCGSERIAL section in f81232_ioctl() to f81232_get_serial_info()
to make it clarify.

Also we fix device type from 16654 to 16550A, and set it's baud_base
to 115200 (1.8432MHz/16)

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 30 +++---
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index e1cdf42..e70ec62 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -516,24 +516,32 @@ static int f81232_carrier_raised(struct usb_serial_port 
*port)
return 0;
 }
 
+static int f81232_get_serial_info(struct usb_serial_port *port,
+   unsigned long arg)
+{
+   struct serial_struct ser;
+
+   memset(&ser, 0, sizeof(ser));
+
+   ser.type = PORT_16550A;
+   ser.line = port->minor;
+   ser.port = port->port_number;
+   ser.baud_base = 115200;
+
+   if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
+   return -EFAULT;
+
+   return 0;
+}
+
 static int f81232_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
 {
-   struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
 
switch (cmd) {
case TIOCGSERIAL:
-   memset(&ser, 0, sizeof ser);
-   ser.type = PORT_16654;
-   ser.line = port->minor;
-   ser.port = port->port_number;
-   ser.baud_base = 460800;
-
-   if (copy_to_user((void __user *)arg, &ser, sizeof ser))
-   return -EFAULT;
-
-   return 0;
+   return f81232_get_serial_info(port, arg);
default:
break;
}
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 07/10] USB: f81232: fix error in f81232_carrier_raised()

2015-02-16 Thread Peter Hung
It's should compared with UART_MSR_DCD, not UART_DCD.
also we clean-up some non-used define to avoid impropriety use.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 16 +---
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index e70ec62..c87a3eb 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,20 +47,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
-#define CONTROL_DTR0x01
-#define CONTROL_RTS0x02
-
-#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
-
 struct f81232_private {
spinlock_t lock;
u8 line_control;
@@ -511,7 +497,7 @@ static void f81232_dtr_rts(struct usb_serial_port *port, 
int on)
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   if (priv->modem_status & UART_DCD)
+   if (priv->modem_status & UART_MSR_DCD)
return 1;
return 0;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 08/10] USB: f81232: fix read MSR strange value

2015-02-16 Thread Peter Hung
When we use RS232 loopback, assume doing RTS change will cause
CTS change, DTR change will cause DCD/DSR change too.

Sometimes we got 7~4 bits of MSR changed but the 3~0 bits of
MSR(delta) maybe not changed when set & get MCR fasterly.

So we add more check not only UART_MSR_ANY_DELTA but also with
comparing DCD/RI/DSR/CTS change with old value. Due to the state
bit is always correct, we direct save msr when read.

The following step to reproduce this problem with while loop step 1~4:
1. ioctl(fd, TIOCMSET, &data) to set RTS or DTR
2. ioctl(fd, TIOCMGET, &data) to read CTS or DCD/DSR state
3. ioctl(fd, TIOCMSET, &data) to unset RTS or DTR
4. ioctl(fd, TIOCMGET, &data) to read CTS or DCD/DSR state

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 23 +--
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c87a3eb..94c05d7 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -110,7 +110,8 @@ static void f81232_read_msr(struct usb_serial_port *port)
 {
int status;
unsigned long flags;
-   u8 current_msr;
+   u8 current_msr, prev_msr;
+   u8 msr_mask = ~UART_MSR_ANY_DELTA;
struct tty_struct *tty;
struct f81232_private *priv = usb_get_serial_port_data(port);
 
@@ -123,7 +124,21 @@ static void f81232_read_msr(struct usb_serial_port *port)
return;
}
 
-   if (!(current_msr & UART_MSR_ANY_DELTA))
+   /*
+   *  The 7~4 bits of MSR will change but the 3~0 bits of MSR(delta)
+   *  maybe not change when set & get MCR fasterly.
+   *
+   *  So we add more check with comparing DCD/RI/DSR/CTS
+   *  change. and direct save msr when read.
+   */
+
+   spin_lock_irqsave(&priv->lock, flags);
+   prev_msr = priv->modem_status;
+   priv->modem_status = current_msr;
+   spin_unlock_irqrestore(&priv->lock, flags);
+
+   if (!(current_msr & UART_MSR_ANY_DELTA) &&
+   !((prev_msr ^ current_msr) & msr_mask))
return;
 
tty = tty_port_tty_get(&port->port);
@@ -136,10 +151,6 @@ static void f81232_read_msr(struct usb_serial_port *port)
tty_kref_put(tty);
}
 
-   spin_lock_irqsave(&priv->lock, flags);
-   priv->modem_status = current_msr;
-   spin_unlock_irqrestore(&priv->lock, flags);
-
wake_up_interruptible(&port->port.delta_msr_wait);
 }
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V5 6/8] USB: f81232: clarify f81232_ioctl()

2015-02-09 Thread Peter Hung

Hello,

Johan Hovold 於 2015/2/9 下午 04:42 寫道:


The value you should be returning is
jiffies_to_msecs(port->port.closing_wait) / 10, unless the value is
ASYNC_CLOSING_WAIT_NONE in which case you simply return that, and
similarly for close_delay.


I'll try to fix it, or reuse default value next version.


Make sure to update the commit log for the next revision so that it
describes what you actually do.

I will probably not have time to review this version this week I'm
afraid.


OK, I'll review it again, fix and resend it after Chinese New Year (2/23+).

Thanks all seniors.

--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V5 6/8] USB: f81232: clarify f81232_ioctl()

2015-02-08 Thread Peter Hung

Hello,

Sergei Shtylyov 於 2015/2/6 下午 08:21 寫道:

We extract TIOCGSERIAL section in f81232_ioctl() to
f81232_get_serial_info()
to make it clarify


You're also changing 'ser.baud_rate' from 460800 to 115200. And
explicitly overriding some previously initialized to 0 fields.


F81232 max baudrate is only 115200bps, so I set it for
1.8432MHz/16 = 115200.

We had add some closing time referenced from serial_core.c. The default
value is:

port->close_delay = HZ / 2;  /* .5 seconds */
port->closing_wait= 30 * HZ;/* 30 seconds */

We had increasing close_delay about 10x to

port->close_delay = 5 * HZ ;




The f81232_set_mctrl() replace set_control_lines() to do MCR control
so we clean-up the set_control_lines() function.


I don't see where are you doing this...



This text is my patch V5 5/8 second section. I had wrong operation of 
copy & paste. It's doesn't need for this patch, sorry for it.


--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V5 0/8] USB: f81534: v5 patch

2015-02-06 Thread Peter Hung
This series patch V5 is improvement from V4 as following:

1. transform all function not to use private data as parameter, using
   usb_serial_port instead.

2. Some init step we extract it from set_term() to f81232_port_init()
   and run it when open port only.

3. We'll force re-read msr in tiocmget() because the IIR with MSR change
   maybe delay received.

4. process_read_urb() add process of Break/FrameError/ParityError.

5. clarify a lot of code about Johan suggested.

Peter Hung (8):
  USB: f81232: Rename private struct member name
  USB: f81232: implement read IIR/MSR with endpoint
  USB: f81232: implement RX bulk-in ep
  USB: f81232: implement set_termios
  USB: f81232: implement MCR/MSR function
  USB: f81232: clarify f81232_ioctl()
  USB: f81232: fix error in f81232_carrier_raised()
  USB: f81232: modify/add author

 drivers/usb/serial/f81232.c | 471 +++-
 1 file changed, 375 insertions(+), 96 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V5 1/8] USB: f81232: Rename private struct member name

2015-02-06 Thread Peter Hung
Change private struct member name from line_status to modem_status.
It will store MSR for some functions used

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c5dc233..669a2f2 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,7 +47,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 struct f81232_private {
spinlock_t lock;
u8 line_control;
-   u8 line_status;
+   u8 modem_status;
 };
 
 static void f81232_update_line_status(struct usb_serial_port *port,
@@ -113,8 +113,8 @@ static void f81232_process_read_urb(struct urb *urb)
 
/* update line status */
spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->line_status;
-   priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+   line_status = priv->modem_status;
+   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
 
if (!urb->actual_length)
@@ -241,7 +241,7 @@ static void f81232_dtr_rts(struct usb_serial_port *port, 
int on)
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   if (priv->line_status & UART_DCD)
+   if (priv->modem_status & UART_DCD)
return 1;
return 0;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V5 3/8] USB: f81232: implement RX bulk-in ep

2015-02-06 Thread Peter Hung
The F81232 bulk-in is RX data + LSR channel, data format is
[LSR+Data][LSR+Data]. , We had reimplemented in this patch.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 68 +++--
 1 file changed, 35 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index ec4609d..9ea498a 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -185,44 +185,46 @@ exit:
 static void f81232_process_read_urb(struct urb *urb)
 {
struct usb_serial_port *port = urb->context;
-   struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
-   char tty_flag = TTY_NORMAL;
-   unsigned long flags;
-   u8 line_status;
+   char tty_flag;
int i;
 
-   /* update line status */
-   spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->modem_status;
-   priv->modem_status &= ~UART_STATE_TRANSIENT_MASK;
-   spin_unlock_irqrestore(&priv->lock, flags);
-
-   if (!urb->actual_length)
+   if (urb->actual_length < 2)
return;
 
-   /* break takes precedence over parity, */
-   /* which takes precedence over framing errors */
-   if (line_status & UART_BREAK_ERROR)
-   tty_flag = TTY_BREAK;
-   else if (line_status & UART_PARITY_ERROR)
-   tty_flag = TTY_PARITY;
-   else if (line_status & UART_FRAME_ERROR)
-   tty_flag = TTY_FRAME;
-   dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
-
-   /* overrun is special, not associated with a char */
-   if (line_status & UART_OVERRUN_ERROR)
-   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
-   if (port->port.console && port->sysrq) {
-   for (i = 0; i < urb->actual_length; ++i)
-   if (!usb_serial_handle_sysrq_char(port, data[i]))
-   tty_insert_flip_char(&port->port, data[i],
-   tty_flag);
-   } else {
-   tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
-   urb->actual_length);
+   /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
+
+   for (i = 0 ; i < urb->actual_length ; i += 2) {
+   tty_flag = TTY_NORMAL;
+
+   if (unlikely(data[i+0] & UART_LSR_BRK_ERROR_BITS)) {
+   if (data[i+0] & UART_LSR_BI) {
+   tty_flag = TTY_BREAK;
+   port->icount.brk++;
+   usb_serial_handle_break(port);
+   } else if (data[i+0] & UART_LSR_PE) {
+   tty_flag = TTY_PARITY;
+   port->icount.parity++;
+   } else if (data[i+0] & UART_LSR_FE) {
+   tty_flag = TTY_FRAME;
+   port->icount.frame++;
+   }
+
+   if (data[0] & UART_LSR_OE) {
+   port->icount.overrun++;
+   tty_insert_flip_char(&port->port, 0,
+   TTY_OVERRUN);
+   }
+   }
+
+   if (port->port.console && port->sysrq) {
+   if (!usb_serial_handle_sysrq_char(port, data[i+1]))
+   tty_insert_flip_char(&port->port, data[i+1],
+   tty_flag);
+   } else {
+   tty_insert_flip_string_fixed_flag(&port->port,
+   &data[i+1], tty_flag, 1);
+   }
}
 
tty_flip_buffer_push(&port->port);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V5 7/8] USB: f81232: fix error in f81232_carrier_raised()

2015-02-06 Thread Peter Hung
It's should compared with UART_MSR_DCD, not UART_DCD.
also we clean-up some non-used define to avoid impropriety use.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 16 +---
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 4dddb44..07abf0c 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -47,20 +47,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
-#define CONTROL_DTR0x01
-#define CONTROL_RTS0x02
-
-#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
-
 struct f81232_private {
spinlock_t lock;
u8 line_control;
@@ -511,7 +497,7 @@ static void f81232_dtr_rts(struct usb_serial_port *port, 
int on)
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   if (priv->modem_status & UART_DCD)
+   if (priv->modem_status & UART_MSR_DCD)
return 1;
return 0;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V5 4/8] USB: f81232: implement set_termios

2015-02-06 Thread Peter Hung
The original driver had do not any h/w change in driver.
This patch implements with configure H/W for
baud/parity/word length/stop bits functional.

Some init step extract to f81232_port_init(), called once with open().
And refine baudrate setting to f81232_set_baudrate()

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 145 +---
 1 file changed, 138 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 9ea498a..06d1eb0 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -31,11 +31,19 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* Maximum baudrate for F81232 */
+#define F81232_MAX_BAUDRATE 115200L
+
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST 0xA0
 #define F81232_GET_REGISTER 0xc0
+#define F81232_SET_REGISTER 0x40
 
 #define SERIAL_BASE_ADDRESS   0x0120
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
 #define CONTROL_DTR0x01
@@ -61,6 +69,14 @@ struct f81232_private {
struct usb_serial_port *port;
 };
 
+static int calc_baud_divisor(u32 baudrate)
+{
+   if (!baudrate)
+   return 0;
+   else
+   return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate);
+}
+
 static int f81232_get_register(struct usb_serial_port *port,
  u16 reg, u8 *data)
 {
@@ -82,6 +98,27 @@ static int f81232_get_register(struct usb_serial_port *port,
return status;
 }
 
+static int f81232_set_register(struct usb_serial_port *port,
+ u16 reg, u8 data)
+{
+   int status;
+   struct usb_device *dev = port->serial->dev;
+
+   status = usb_control_msg(dev,
+   usb_sndctrlpipe(dev, 0),
+   F81232_REGISTER_REQUEST,
+   F81232_SET_REGISTER,
+   reg,
+   0,
+   &data,
+   sizeof(data),
+   USB_CTRL_SET_TIMEOUT);
+   if (status < 0)
+   dev_err(&port->dev, "%s status: %d\n", __func__, status);
+
+   return status;
+}
+
 static void f81232_read_msr(struct usb_serial_port *port)
 {
int status;
@@ -247,18 +284,106 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 */
 }
 
+static void f81232_set_baudrate(struct usb_serial_port *port, int baudrate)
+{
+   u8 divisor;
+   int status = 0;
+
+   divisor = calc_baud_divisor(baudrate);
+
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+UART_LCR_DLAB); /* DLAB */
+   if (status < 0) {
+   dev_err(&port->dev, "%s status: %d line:%d\n",
+   __func__, status, __LINE__);
+   }
+
+   status = f81232_set_register(port, RECEIVE_BUFFER_REGISTER,
+divisor & 0x00ff); /* low */
+   if (status < 0) {
+   dev_err(&port->dev, "%s status: %d line:%d\n",
+   __func__, status, __LINE__);
+   }
+
+   status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER,
+(divisor & 0xff00) >> 8); /* high */
+   if (status < 0) {
+   dev_err(&port->dev, "%s status: %d line:%d\n", __func__,
+   status, __LINE__);
+   }
+
+   status = f81232_set_register(port, LINE_CONTROL_REGISTER, 0x00);
+   if (status < 0) {
+   dev_err(&port->dev, "%s status: %d line:%d\n", __func__,
+   status, __LINE__);
+   }
+}
+
+static int f81232_port_init(struct usb_serial_port *port)
+{
+   u8 data;
+   int status = 0;
+
+   /* fifo on, trigger8, clear TX/RX*/
+   data = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR
+   | UART_FCR_CLEAR_XMIT;
+
+   status |= f81232_set_register(port, FIFO_CONTROL_REGISTER, data);
+
+   /* MSR Interrupt only, LSR will read from Bulk-in odd byte */
+   data = UART_IER_MSI;
+
+   /* IER */
+   status |= f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, data);
+   if (status < 0) {
+   dev_err(&port->dev, "%s set error: %d\n", __func__, status);
+   return status;
+   }
+
+   return 0;
+}
+
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios

[PATCH V5 2/8] USB: f81232: implement read IIR/MSR with endpoint

2015-02-06 Thread Peter Hung
The interrupt Endpoint will report current IIR. If we got IIR with MSR Changed
, We will do read MSR with interrupt_work worker to do f81232_read_msr() func.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 109 
 1 file changed, 100 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 669a2f2..ec4609d 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 
 static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1934, 0x0706) },
@@ -30,6 +31,13 @@ static const struct usb_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+/* USB Control EP parameter */
+#define F81232_REGISTER_REQUEST 0xA0
+#define F81232_GET_REGISTER 0xc0
+
+#define SERIAL_BASE_ADDRESS   0x0120
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
+
 #define CONTROL_DTR0x01
 #define CONTROL_RTS0x02
 
@@ -48,19 +56,92 @@ struct f81232_private {
spinlock_t lock;
u8 line_control;
u8 modem_status;
+
+   struct work_struct interrupt_work;
+   struct usb_serial_port *port;
 };
 
-static void f81232_update_line_status(struct usb_serial_port *port,
+static int f81232_get_register(struct usb_serial_port *port,
+ u16 reg, u8 *data)
+{
+   int status;
+   struct usb_device *dev = port->serial->dev;
+
+   status = usb_control_msg(dev,
+usb_rcvctrlpipe(dev, 0),
+F81232_REGISTER_REQUEST,
+F81232_GET_REGISTER,
+reg,
+0,
+data,
+sizeof(*data),
+USB_CTRL_GET_TIMEOUT);
+   if (status < 0)
+   dev_err(&port->dev, "%s status: %d\n", __func__, status);
+
+   return status;
+}
+
+static void f81232_read_msr(struct usb_serial_port *port)
+{
+   int status;
+   unsigned long flags;
+   u8 current_msr;
+   struct tty_struct *tty;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   status = f81232_get_register(port, MODEM_STATUS_REGISTER,
+   ¤t_msr);
+   if (status < 0) {
+   /* Retain the error even reported in f81232_get_register()
+to make debug easily :D */
+   dev_err(&port->dev, "%s fail, status: %d\n", __func__, status);
+   return;
+   }
+
+   if (!(current_msr & UART_MSR_ANY_DELTA))
+   return;
+
+   tty = tty_port_tty_get(&port->port);
+   if (tty) {
+   if (current_msr & UART_MSR_DDCD) {
+   usb_serial_handle_dcd_change(port, tty,
+   current_msr & UART_MSR_DCD);
+   }
+
+   tty_kref_put(tty);
+   }
+
+   spin_lock_irqsave(&priv->lock, flags);
+   priv->modem_status = current_msr;
+   spin_unlock_irqrestore(&priv->lock, flags);
+
+   wake_up_interruptible(&port->port.delta_msr_wait);
+}
+
+static void f81232_update_modem_status(struct usb_serial_port *port,
  unsigned char *data,
  unsigned int actual_length)
 {
-   /*
-* FIXME: Update port->icount, and call
-*
-*  wake_up_interruptible(&port->port.delta_msr_wait);
-*
-*on MSR changes.
-*/
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (!actual_length)
+   return;
+
+   switch (data[0] & 0x07) {
+   case 0x00: /* msr change */
+   dev_dbg(&port->dev, "IIR: MSR Change: %x\n", data[0]);
+   schedule_work(&priv->interrupt_work);
+   break;
+   case 0x02: /* tx-empty */
+   break;
+   case 0x04: /* rx data available */
+   break;
+   case 0x06: /* lsr change */
+   /* we can forget it. the LSR will read from bulk-in */
+   dev_dbg(&port->dev, "IIR: LSR Change: %x\n", data[0]);
+   break;
+   }
 }
 
 static void f81232_read_int_callback(struct urb *urb)
@@ -91,7 +172,7 @@ static void f81232_read_int_callback(struct urb *urb)
usb_serial_debug_data(&port->dev, __func__,
  urb->actual_length, urb->transfer_buffer);
 
-   f81232_update_line_status(port, data, actual_length);
+   f81232_update_modem_status(port, data, actual_length);
 
 exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -270,6 +351,14 @@ static int f81232_ioctl(struct tty_struct *tty,
retur

[PATCH V5 5/8] USB: f81232: implement MCR/MSR function

2015-02-06 Thread Peter Hung
This patch implement relative MCR/MSR function, such like
tiocmget()/tiocmset()/dtr_rts().

The f81232_set_mctrl() replace set_control_lines() to do MCR control
so we clean-up the set_control_lines() function.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 98 +++--
 1 file changed, 77 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 06d1eb0..e1cdf42 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -44,6 +44,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
 #define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
 #define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 
 #define CONTROL_DTR0x01
@@ -156,6 +157,50 @@ static void f81232_read_msr(struct usb_serial_port *port)
wake_up_interruptible(&port->port.delta_msr_wait);
 }
 
+static int f81232_set_mctrl(struct usb_serial_port *port,
+  unsigned int set, unsigned int clear)
+{
+   u8 urb_value;
+   int status;
+   unsigned long flags;
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+
+   if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0)
+   return 0;   /* no change */
+
+   /* 'set' takes precedence over 'clear' */
+   clear &= ~set;
+
+   /* force enable interrupt with OUT2 */
+   urb_value = UART_MCR_OUT2 | priv->line_control;
+
+   if (clear & TIOCM_DTR)
+   urb_value &= ~UART_MCR_DTR;
+
+   if (clear & TIOCM_RTS)
+   urb_value &= ~UART_MCR_RTS;
+
+   if (set & TIOCM_DTR)
+   urb_value |= UART_MCR_DTR;
+
+   if (set & TIOCM_RTS)
+   urb_value |= UART_MCR_RTS;
+
+   dev_dbg(&port->dev, "%s new:%02x old:%02x\n", __func__,
+   urb_value, priv->line_control);
+
+   status = f81232_set_register(port, MODEM_CONTROL_REGISTER, urb_value);
+   if (status < 0) {
+   dev_err(&port->dev, "%s set MCR status < 0\n", __func__);
+   } else {
+   spin_lock_irqsave(&priv->lock, flags);
+   priv->line_control = urb_value;
+   spin_unlock_irqrestore(&priv->lock, flags);
+   }
+
+   return status;
+}
+
 static void f81232_update_modem_status(struct usb_serial_port *port,
  unsigned char *data,
  unsigned int actual_length)
@@ -267,12 +312,6 @@ static void f81232_process_read_urb(struct urb *urb)
tty_flip_buffer_push(&port->port);
 }
 
-static int set_control_lines(struct usb_device *dev, u8 value)
-{
-   /* FIXME - Stubbed out for now */
-   return 0;
-}
-
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
/* FIXME - Stubbed out for now */
@@ -388,15 +427,41 @@ static void f81232_set_termios(struct tty_struct *tty,
 
 static int f81232_tiocmget(struct tty_struct *tty)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int r;
+   struct usb_serial_port *port = tty->driver_data;
+   struct f81232_private *port_priv = usb_get_serial_port_data(port);
+   unsigned long flags;
+   u8 mcr, msr;
+
+   /* force get current MSR changed state */
+   f81232_read_msr(port);
+
+   spin_lock_irqsave(&port_priv->lock, flags);
+   mcr = port_priv->line_control;
+   msr = port_priv->modem_status;
+   spin_unlock_irqrestore(&port_priv->lock, flags);
+
+   r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) |
+   (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) |
+   (msr & UART_MSR_CTS ? TIOCM_CTS : 0) |
+   (msr & UART_MSR_DCD ? TIOCM_CAR : 0) |
+   (msr & UART_MSR_RI ? TIOCM_RI : 0) |
+   (msr & UART_MSR_DSR ? TIOCM_DSR : 0);
+
+   return r;
 }
 
 static int f81232_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int status;
+   struct usb_serial_port *port = tty->driver_data;
+
+   status = f81232_set_mctrl(port, set, clear);
+   if (status < 0)
+   return usb_translate_errors(status);
+   else
+   return 0;
 }
 
 static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -437,19 +502,10 @@ static void f81232_close(struct usb_serial_port *port)
 
 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 {
-   struct f81232_private *priv = usb_get_serial_port_data(port);

[PATCH V5 8/8] USB: f81232: modify/add author

2015-02-06 Thread Peter Hung
Add me to co-author and fix no '>' in greg kh's email

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 07abf0c..8799b66 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -608,5 +608,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
-MODULE_AUTHOR("Greg Kroah-Hartman ");
+MODULE_AUTHOR("Peter Hong ");
 MODULE_LICENSE("GPL v2");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V5 6/8] USB: f81232: clarify f81232_ioctl()

2015-02-06 Thread Peter Hung
We extract TIOCGSERIAL section in f81232_ioctl() to f81232_get_serial_info()
to make it clarify

The f81232_set_mctrl() replace set_control_lines() to do MCR control
so we clean-up the set_control_lines() function.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 34 +++---
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index e1cdf42..4dddb44 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -516,24 +516,36 @@ static int f81232_carrier_raised(struct usb_serial_port 
*port)
return 0;
 }
 
+static int f81232_get_serial_info(struct usb_serial_port *port,
+   unsigned long arg)
+{
+   struct serial_struct ser;
+
+   memset(&ser, 0, sizeof(ser));
+
+   ser.flags   = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+   ser.xmit_fifo_size  = port->bulk_out_size;
+   ser.close_delay = 5 * HZ;
+   ser.closing_wait= 30 * HZ;
+   ser.type = PORT_16550A;
+   ser.line = port->minor;
+   ser.port = port->port_number;
+   ser.baud_base = 115200;
+
+   if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
+   return -EFAULT;
+
+   return 0;
+}
+
 static int f81232_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
 {
-   struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
 
switch (cmd) {
case TIOCGSERIAL:
-   memset(&ser, 0, sizeof ser);
-   ser.type = PORT_16654;
-   ser.line = port->minor;
-   ser.port = port->port_number;
-   ser.baud_base = 460800;
-
-   if (copy_to_user((void __user *)arg, &ser, sizeof ser))
-   return -EFAULT;
-
-   return 0;
+   return f81232_get_serial_info(port, arg);
default:
break;
}
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 2/7] usb: serial: modify author for F81232

2015-01-29 Thread Peter Hung
add co-author and fix no '>' in greg kh's email

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 4f42e9d..9ef9775 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -330,5 +330,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
-MODULE_AUTHOR("Greg Kroah-Hartman ");
+MODULE_AUTHOR("Peter Hong ");
 MODULE_LICENSE("GPL v2");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 1/7] usb: serial: modify bulk-in/out size for F81232

2015-01-29 Thread Peter Hung
The F81232 real bulk-in/out ep buffer size is 64Bytes

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c5dc233..4f42e9d 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -304,8 +304,8 @@ static struct usb_serial_driver f81232_device = {
},
.id_table = id_table,
.num_ports =1,
-   .bulk_in_size = 256,
-   .bulk_out_size =256,
+   .bulk_in_size = 64,
+   .bulk_out_size =64,
.open = f81232_open,
.close =f81232_close,
.dtr_rts =  f81232_dtr_rts,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 5/7] usb: serial: implement set_termios for F81232

2015-01-29 Thread Peter Hung
The original driver had do not any h/w change in driver.
This patch implements with configure H/W for
baud/parity/word length/stop bits functional.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 144 +---
 1 file changed, 137 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 12e1ae4..248f40d 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -51,6 +51,10 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_USB_TIMEOUT 3000
 
 #define SERIAL_BASE_ADDRESS   (0x0120)
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 struct f81232_private {
spinlock_t lock;
@@ -61,6 +65,20 @@ struct f81232_private {
struct usb_serial_port *port;
 };
 
+static inline int calc_baud_divisor(u32 baudrate)
+{
+   u32 divisor, rem;
+
+   divisor = 115200L / baudrate;
+   rem = 115200L % baudrate;
+
+   /* Round to nearest divisor */
+   if (((rem * 2) >= baudrate) && (baudrate != 110))
+   divisor++;
+
+   return divisor;
+}
+
 static inline int f81232_get_register(struct usb_device *dev,
  u16 reg, u8 *data)
 {
@@ -84,6 +102,29 @@ static inline int f81232_get_register(struct usb_device 
*dev,
return status;
 }
 
+static inline int f81232_set_register(struct usb_device *dev,
+ u16 reg, u8 data)
+{
+   int status;
+
+   status = usb_control_msg(dev,
+   usb_sndctrlpipe(dev, 0),
+   REGISTER_REQUEST,
+   SET_REGISTER,
+   reg,
+   0,
+   &data,
+   1,
+   F81232_USB_TIMEOUT);
+
+   if (status < 0) {
+   dev_dbg(&dev->dev,
+   "%s status: %d\n", __func__, status);
+   }
+
+   return status;
+}
+
 static void f81232_read_msr(struct f81232_private *priv)
 {
int status;
@@ -240,15 +281,104 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
 {
-   /* FIXME - Stubbed out for now */
+   u16 divisor;
+   u16 new_lcr = 0;
+   u8 data;
+   int status;
+   struct ktermios *termios = &tty->termios;
+   struct usb_device *dev = port->serial->dev;
+   unsigned int cflag = termios->c_cflag;
 
-   /* Don't change anything if nothing has changed */
-   if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
-   return;
+   divisor = calc_baud_divisor(tty_get_baud_rate(tty));
+
+   status = f81232_set_register(dev, LINE_CONTROL_REGISTER,
+UART_LCR_DLAB); /* DLAB */
+
+   if (status < 0) {
+   dev_dbg(&dev->dev,
+   "%s status: %d line:%d\n", __func__, status, __LINE__);
+   }
+
+   status = f81232_set_register(dev, RECEIVE_BUFFER_REGISTER,
+divisor & 0x00ff); /* low */
+
+   if (status < 0) {
+   dev_dbg(&dev->dev,
+   "%s status: %d line:%d\n", __func__, status, __LINE__);
+   }
+
+   status = f81232_set_register(dev, INTERRUPT_ENABLE_REGISTER,
+(divisor & 0xff00) >> 8); /* high */
+
+   if (status < 0) {
+   dev_dbg(&dev->dev,
+   "%s status: %d line:%d\n", __func__, status, __LINE__);
+   }
+
+   status = f81232_set_register(dev, LINE_CONTROL_REGISTER, 0x00);
+
+   if (status < 0) {
+   dev_dbg(&dev->dev,
+   "%s status: %d line:%d\n", __func__, status, __LINE__);
+   }
+
+   if (cflag & PARENB) {
+   new_lcr |= UART_LCR_PARITY; /* default parity on/odd */
+
+   if (cflag & CMSPAR) {
+   if (cflag & PARODD) {
+   /* stick mark */
+   new_lcr |= UART_LCR_SPAR;
+   } else {
+/* stick space */
+   new_lcr |= (UART_LCR_EPAR | UART_LCR_SPAR);
+   }
+   } else {
+   if (!(cflag & PARODD)) {
+   /* even */
+   new_lcr

[PATCH v4 6/7] usb: serial: implement MCR/MSR function for F81232

2015-01-29 Thread Peter Hung
This patch implement relative MCR/MSR function, such like
tiocmget()/tiocmset()/dtr_rts().

The update_mctrl() replace set_control_lines() to do MCR control
so we clean-up the set_control_lines() function.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 105 ++--
 1 file changed, 83 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 248f40d..0ed7e36 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -38,11 +38,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #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
 
 #define REGISTER_REQUEST 0xA0
@@ -55,6 +51,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
 #define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
 #define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 struct f81232_private {
spinlock_t lock;
@@ -165,6 +162,62 @@ static void f81232_read_msr(struct f81232_private *priv)
 
dev_dbg(&dev->dev, "%s: %x\n", __func__, priv->line_status);
 }
+
+static inline int update_mctrl(struct f81232_private *port_priv,
+  unsigned int set, unsigned int clear)
+{
+   struct usb_device *dev = port_priv->port->serial->dev;
+   u8 urb_value;
+   int status;
+   unsigned long flags;
+
+   if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
+   dev_dbg(&dev->dev, "%s fail - DTR|RTS %d\n",
+   __func__, __LINE__);
+   return 0;   /* no change */
+   }
+
+   clear &= ~set;  /* 'set' takes precedence over 'clear' */
+   urb_value = 8 | port_priv->line_control;
+
+   if (clear & TIOCM_DTR) {
+   urb_value &= ~UART_MCR_DTR;
+   dev_dbg(&dev->dev, "clear DTR\n");
+   }
+
+   if (clear & TIOCM_RTS) {
+   urb_value &= ~UART_MCR_RTS;
+   dev_dbg(&dev->dev, "clear RTS\n");
+   }
+
+   if (set & TIOCM_DTR) {
+   urb_value |= UART_MCR_DTR;
+   dev_dbg(&dev->dev, "set DTR\n");
+   }
+
+   if (set & TIOCM_RTS) {
+   urb_value |= UART_MCR_RTS;
+   dev_dbg(&dev->dev, "set RTS\n");
+   }
+
+   dev_dbg(&dev->dev, "%s n:%x o:%x\n", __func__, urb_value,
+   port_priv->line_control);
+
+   status = f81232_set_register(dev, MODEM_CONTROL_REGISTER, urb_value);
+
+   if (status < 0) {
+   dev_dbg(&dev->dev, "%s read MSR status < 0\n", __func__);
+   } else {
+   spin_lock_irqsave(&port_priv->lock, flags);
+   port_priv->line_control = urb_value;
+   spin_unlock_irqrestore(&port_priv->lock, flags);
+   }
+
+   f81232_read_msr(port_priv);
+
+   return status;
+}
+
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
  unsigned int actual_length)
@@ -261,12 +314,6 @@ static void f81232_process_read_urb(struct urb *urb)
 
 }
 
-static int set_control_lines(struct usb_device *dev, u8 value)
-{
-   /* FIXME - Stubbed out for now */
-   return 0;
-}
-
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
/* FIXME - Stubbed out for now */
@@ -383,14 +430,35 @@ static void f81232_set_termios(struct tty_struct *tty,
 
 static int f81232_tiocmget(struct tty_struct *tty)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int r;
+   struct usb_serial_port *port = tty->driver_data;
+   struct f81232_private *port_priv = usb_get_serial_port_data(port);
+   unsigned long flags;
+   u8 mcr, msr;
+
+   spin_lock_irqsave(&port_priv->lock, flags);
+   mcr = port_priv->line_control;
+   msr = port_priv->line_status;
+   spin_unlock_irqrestore(&port_priv->lock, flags);
+
+   r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) |
+   (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) |
+   (msr & UART_MSR_CTS ? TIOCM_CTS : 0) |
+   (msr & UART_MSR_DCD ? TIOCM_CAR : 0) |
+   (msr & UART_MSR_R

[PATCH v4 4/7] usb: serial: reimplement RX bulk-in ep for F81232

2015-01-29 Thread Peter Hung
The F81232 bulk-in is RX data channel. Data format is
[LSR+Data][LSR+Data]. , We had reimplemented in this patch.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 47 +++--
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 274120d..12e1ae4 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -194,47 +194,30 @@ exit:
 static void f81232_process_read_urb(struct urb *urb)
 {
struct usb_serial_port *port = urb->context;
-   struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
char tty_flag = TTY_NORMAL;
-   unsigned long flags;
-   u8 line_status;
+   u8 line_status = 0;
int i;
 
-   /* update line status */
-   spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->line_status;
-   priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
-   spin_unlock_irqrestore(&priv->lock, flags);
-
if (!urb->actual_length)
return;
 
-   /* break takes precedence over parity, */
-   /* which takes precedence over framing errors */
-   if (line_status & UART_BREAK_ERROR)
-   tty_flag = TTY_BREAK;
-   else if (line_status & UART_PARITY_ERROR)
-   tty_flag = TTY_PARITY;
-   else if (line_status & UART_FRAME_ERROR)
-   tty_flag = TTY_FRAME;
-   dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
-
-   /* overrun is special, not associated with a char */
-   if (line_status & UART_OVERRUN_ERROR)
-   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
-   if (port->port.console && port->sysrq) {
-   for (i = 0; i < urb->actual_length; ++i)
-   if (!usb_serial_handle_sysrq_char(port, data[i]))
-   tty_insert_flip_char(&port->port, data[i],
-   tty_flag);
-   } else {
-   tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
-   urb->actual_length);
+   /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
+
+   if (urb->actual_length >= 2) {
+
+   for (i = 0 ; i < urb->actual_length ; i += 2) {
+   line_status |= data[i+0];
+   tty_insert_flip_string_fixed_flag(&port->port,
+   &data[i+1], tty_flag, 1);
+   }
+
+   if (unlikely(line_status & UART_LSR_OE))
+   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
+
+   tty_flip_buffer_push(&port->port);
}
 
-   tty_flip_buffer_push(&port->port);
 }
 
 static int set_control_lines(struct usb_device *dev, u8 value)
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 3/7] usb: serial: implement read IIR/MSR ep for F81232

2015-01-29 Thread Peter Hung
The F81232 interrupt ep will continuously report IIR register value.
We had implement the interrupt callback to read IIR, If noticed with
MSR change, we will call worker to read MSR later.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 114 +---
 1 file changed, 107 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 9ef9775..274120d 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 
 static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1934, 0x0706) },
@@ -44,23 +45,112 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define UART_OVERRUN_ERROR 0x40
 #define UART_CTS   0x80
 
+#define REGISTER_REQUEST 0xA0
+#define GET_REGISTER 0xc0
+#define SET_REGISTER 0x40
+#define F81232_USB_TIMEOUT 3000
+
+#define SERIAL_BASE_ADDRESS   (0x0120)
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
 struct f81232_private {
spinlock_t lock;
u8 line_control;
u8 line_status;
+
+   struct work_struct int_worker;
+   struct usb_serial_port *port;
 };
 
+static inline int f81232_get_register(struct usb_device *dev,
+ u16 reg, u8 *data)
+{
+   int status;
+
+   status = usb_control_msg(dev,
+usb_rcvctrlpipe(dev, 0),
+REGISTER_REQUEST,
+GET_REGISTER,
+reg,
+0,
+data,
+sizeof(*data),
+F81232_USB_TIMEOUT);
+
+   if (status < 0) {
+   dev_dbg(&dev->dev,
+   "%s status: %d\n", __func__, status);
+   }
+
+   return status;
+}
+
+static void f81232_read_msr(struct f81232_private *priv)
+{
+   int status;
+   unsigned long flags;
+   u8 current_msr, old_msr;
+   struct usb_device *dev = priv->port->serial->dev;
+   struct tty_struct *tty;
+
+   status = f81232_get_register(dev, MODEM_STATUS_REGISTER, ¤t_msr);
+
+   if (status < 0) {
+   dev_dbg(&dev->dev, "%s fail, status: %d\n", __func__, status);
+   return;
+   }
+
+   spin_lock_irqsave(&priv->lock, flags);
+   old_msr = priv->line_status;
+   spin_unlock_irqrestore(&priv->lock, flags);
+
+   if (current_msr & UART_MSR_ANY_DELTA) {
+   tty = tty_port_tty_get(&priv->port->port);
+
+   if (tty) {
+   if (current_msr & UART_MSR_DDCD) {
+   usb_serial_handle_dcd_change(priv->port,
+   tty, current_msr & UART_MSR_DCD);
+   }
+
+   tty_kref_put(tty);
+   }
+
+   spin_lock_irqsave(&priv->lock, flags);
+   priv->line_status = current_msr;
+   spin_unlock_irqrestore(&priv->lock, flags);
+
+   wake_up_interruptible(&priv->port->port.delta_msr_wait);
+   }
+
+   dev_dbg(&dev->dev, "%s: %x\n", __func__, priv->line_status);
+}
 static void f81232_update_line_status(struct usb_serial_port *port,
  unsigned char *data,
  unsigned int actual_length)
 {
-   /*
-* FIXME: Update port->icount, and call
-*
-*  wake_up_interruptible(&port->port.delta_msr_wait);
-*
-*on MSR changes.
-*/
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+   struct usb_device *dev = port->serial->dev;
+
+   if (!actual_length)
+   return;
+
+   switch (data[0] & 0x07) {
+   case 0x00: /* msr change */
+   dev_dbg(&dev->dev, "IIR: MSR Change: %x\n", data[0]);
+   schedule_work(&priv->int_worker);
+   break;
+
+   case 0x02: /* tx-empty */
+   break;
+
+   case 0x04: /* rx data available */
+   break;
+
+   case 0x06: /* lsr change */
+   /* we can forget it. the LSR will read from bulk-in */
+   dev_dbg(&dev->dev, "IIR: LSR Change: %x\n", data[0]);
+   break;
+   }
 }
 
 static void f81232_read_int_callback(struct urb *urb)
@@ -270,6 +360,14 @@ static int f81232_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
 }
 
+static void f81232_int_work_wq(struct work_struct *work)
+{
+   struct f81232_private *priv =
+   container_of(work, struct f81232_private, int_worker);
+
+   f81232_read_msr(priv);
+}
+
 static int f81232_port_probe(struct u

[PATCH v4 7/7] usb: serial: modify ioctl TIOCGSERIAL for F81232

2015-01-29 Thread Peter Hung
Set correct product type from 16654 to 16550A and
fix the ioctl TIOCGSERIAL return struct values.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 13 +
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 0ed7e36..4d3aba8 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -518,13 +518,18 @@ static int f81232_ioctl(struct tty_struct *tty,
 
switch (cmd) {
case TIOCGSERIAL:
-   memset(&ser, 0, sizeof ser);
-   ser.type = PORT_16654;
+   memset(&ser, 0, sizeof(ser));
+   ser.flags   = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+   ser.xmit_fifo_size  = port->bulk_out_size;
+   ser.close_delay = 5*HZ;
+   ser.closing_wait= 30*HZ;
+
+   ser.type = PORT_16550A;
ser.line = port->minor;
ser.port = port->port_number;
-   ser.baud_base = 460800;
+   ser.baud_base = 115200;
 
-   if (copy_to_user((void __user *)arg, &ser, sizeof ser))
+   if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
return -EFAULT;
 
return 0;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 1/5] usb: serial: add register map for F81232

2015-01-28 Thread Peter Hung

Hello.

1. For retry Issue:

These patches is referenced from our other usb serial product. That 
product maybe not ack the control ep command when It's in very heavily 
loading. Our workaround is to modify driver to retry more times if it 
timeout because it's f/w can't upgrade with usb protocol. I will remove 
the retry mechanic and test for it again.


2. For some function/variable not used:

The original driver is lacking a lot of feature. My first patch strategy 
is putting all needed function / variables in patch 1 and apply it in 
following patches. Sorry for my wrong strategy, I'll change it with more 
meaningful and logical patchset and resend it.


Thanks for your patient and advice.

Johan Hovold 於 2015/1/29 上午 01:55 寫道:

On Wed, Jan 28, 2015 at 01:57:56PM +0800, Peter Hung wrote:

Add register map for F81232. and add some function to operating this device.
etc. f81232_get_register()/f81232_set_register() to work with USB control
point. and worker f81232_int_work_wq() to read MSR when IIR acquired.

Signed-off-by: Peter Hung 
---
  drivers/usb/serial/f81232.c | 229 +---
  1 file changed, 214 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c5dc233..efd45a7 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -23,6 +23,8 @@
  #include 
  #include 
  #include 
+#include 
+#include 


You don't need this header.


  static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1934, 0x0706) },
@@ -37,19 +39,197 @@ MODULE_DEVICE_TABLE(usb, id_table);
  #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

+#define UART_BREAK_ERROR   0x10
+#define UART_FRAME_ERROR   0x08
+#define UART_PARITY_ERROR  0x04
+#define UART_OVERRUN_ERROR 0x02
+#define  SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)


You never use this define.


+#define REGISTER_REQUEST 0xA0
+#define GET_REGISTER 0xc0
+#define SET_REGISTER 0x40
+#define F81232_USB_TIMEOUT 1000
+#define F81232_USB_RETRY 20


Why on earth are you retrying your control requests 20 times? You never
answered my question to a previous version whether the retries are at
all needed.


+
+#define SERIAL_BASE_ADDRESS   (0x0120)
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
+#define TRANSMIT_HOLDING_REGISTER  (0x00 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_IDENT_REGISTER   (0x02 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
+#define LINE_STATUS_REGISTER   (0x05 + SERIAL_BASE_ADDRESS)
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
+
  struct f81232_private {
spinlock_t lock;
u8 line_control;
u8 line_status;
+
+   struct work_struct int_worker;


You never schedule this work.


+   struct usb_serial_port *port;
  };

+static inline int calc_baud_divisor(u32 baudrate)
+{
+   u32 divisor, rem;
+
+   divisor = 115200L / baudrate;
+   rem = 115200L % baudrate;
+
+   /* Round to nearest divisor */
+   if (((rem * 2) >= baudrate) && (baudrate != 110))
+   divisor++;
+
+   return divisor;
+}


You never use this either.

You need to take more care when preparing your patches. As I already
asked, break them up into logical changes and only add things that you
will actually use.


+
+static inline int f81232_get_register(struct usb_device *dev,
+ u16 reg, u8 *data)
+{
+   int status;
+   int i = F81232_USB_RETRY;
+
+   while (i--) {
+   status = usb_control_msg(dev,
+usb_rcvctrlpipe(dev, 0),
+REGISTER_REQUEST,
+GET_REGISTER,
+reg,
+0,
+data,
+sizeof(*data),
+F81232_USB_TIMEOUT);
+
+   if (status < 0) {
+   dev_dbg(&dev->dev,
+   "f81232_get_register status: %d, fail:%d\n",
+   status, i);
+   } else
+   break;


Missing brackets { } on the else branch.


+   }
+
+   return stat

Re: [PATCH v3 5/5] usb: serial: implement CMSPAR for F81232

2015-01-28 Thread Peter Hung

Hello.

I had using "scripts/checkpatch.pl -f" to scan original f81232.c.
It reported with "quoted string split across lines", so I merge these
2 strings into 1 in patch 1/5. But it still warning with "line over 80 
character", so I had shorted string with this line.


I will refine my patch set again with more attention.
Thanks for your advice.

Sergei Shtylyov 於 2015/1/28 下午 08:31 寫道:

Hello.

On 1/28/2015 8:58 AM, Peter Hung wrote:


This patch implement CMSPAR in set_termios,
and fix some warnning from checkpatch.pl


 Please don't try to do 2 unrelated things in one patch.


Signed-off-by: Peter Hung 
---
  drivers/usb/serial/f81232.c | 21 +++--
  1 file changed, 15 insertions(+), 6 deletions(-)



diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 11a236b..79592d6 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c

[...]

@@ -361,12 +361,21 @@ static void f81232_set_termios(struct tty_struct
*tty,


  if (cflag & PARENB) {
-if (cflag & PARODD)
-new_lcr |= UART_LCR_PARITY; /* odd */
-else
-new_lcr |= SERIAL_EVEN_PARITY; /* even */
+if (cflag & CMSPAR) {
+if (cflag & PARODD)
+new_lcr |= (UART_LCR_PARITY | UART_LCR_SPAR);
+else
+new_lcr |= (SERIAL_EVEN_PARITY
+| UART_LCR_SPAR);
+} else {
+if (cflag & PARODD)
+new_lcr |= UART_LCR_PARITY; /* odd */
+else
+new_lcr |= SERIAL_EVEN_PARITY; /* even */
+}
  }

+


Not needed at all.


  if (cflag & CSTOPB)
  new_lcr |= UART_LCR_STOP;
  else
@@ -445,7 +454,7 @@ static int f81232_open(struct tty_struct *tty,
struct usb_serial_port *port)

  result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
  if (result) {
-dev_err(&port->dev, "failed submitting interrupt urb, error
%d\n",
+dev_err(&port->dev, "failed submitting urb, error %d\n",


What are you fixing here?

WBR, Sergei



--
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 1/5] usb: serial: add register map for F81232

2015-01-27 Thread Peter Hung
Add register map for F81232. and add some function to operating this device.
etc. f81232_get_register()/f81232_set_register() to work with USB control
point. and worker f81232_int_work_wq() to read MSR when IIR acquired.

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 229 +---
 1 file changed, 214 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index c5dc233..efd45a7 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -23,6 +23,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1934, 0x0706) },
@@ -37,19 +39,197 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #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
 
+#define UART_BREAK_ERROR   0x10
+#define UART_FRAME_ERROR   0x08
+#define UART_PARITY_ERROR  0x04
+#define UART_OVERRUN_ERROR 0x02
+#define  SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)
+
+#define REGISTER_REQUEST 0xA0
+#define GET_REGISTER 0xc0
+#define SET_REGISTER 0x40
+#define F81232_USB_TIMEOUT 1000
+#define F81232_USB_RETRY 20
+
+#define SERIAL_BASE_ADDRESS   (0x0120)
+#define RECEIVE_BUFFER_REGISTER(0x00 + SERIAL_BASE_ADDRESS)
+#define TRANSMIT_HOLDING_REGISTER  (0x00 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_ENABLE_REGISTER  (0x01 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_IDENT_REGISTER   (0x02 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER  (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER  (0x03 + SERIAL_BASE_ADDRESS)
+#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
+#define LINE_STATUS_REGISTER   (0x05 + SERIAL_BASE_ADDRESS)
+#define MODEM_STATUS_REGISTER  (0x06 + SERIAL_BASE_ADDRESS)
+
 struct f81232_private {
spinlock_t lock;
u8 line_control;
u8 line_status;
+
+   struct work_struct int_worker;
+   struct usb_serial_port *port;
 };
 
+static inline int calc_baud_divisor(u32 baudrate)
+{
+   u32 divisor, rem;
+
+   divisor = 115200L / baudrate;
+   rem = 115200L % baudrate;
+
+   /* Round to nearest divisor */
+   if (((rem * 2) >= baudrate) && (baudrate != 110))
+   divisor++;
+
+   return divisor;
+}
+
+
+static inline int f81232_get_register(struct usb_device *dev,
+ u16 reg, u8 *data)
+{
+   int status;
+   int i = F81232_USB_RETRY;
+
+   while (i--) {
+   status = usb_control_msg(dev,
+usb_rcvctrlpipe(dev, 0),
+REGISTER_REQUEST,
+GET_REGISTER,
+reg,
+0,
+data,
+sizeof(*data),
+F81232_USB_TIMEOUT);
+
+   if (status < 0) {
+   dev_dbg(&dev->dev,
+   "f81232_get_register status: %d, fail:%d\n",
+   status, i);
+   } else
+   break;
+   }
+
+   return status;
+}
+
+
+static inline int f81232_set_register(struct usb_device *dev,
+ u16 reg, u8 data)
+{
+   int status;
+   int i = F81232_USB_RETRY;
+
+   while (i--) {
+   status = usb_control_msg(dev,
+usb_sndctrlpipe(dev, 0),
+REGISTER_REQUEST,
+SET_REGISTER,
+reg,
+0,
+&data,
+1,
+F81232_USB_TIMEOUT);
+
+   if (status < 0)
+   dev_dbg(&dev->dev,
+   "f81232_set_register status: %d, fail:%d\n",
+   status, i);
+   else
+   break;
+   }
+
+   return status;
+}
+
+static void f81232_read_msr(struct f81232_private *priv)
+{
+   unsigned long flags;
+   u8 current_msr, old_msr;
+   struct usb_device *dev = priv->port->serial->dev;
+
+   f81232_get_register(dev, MODEM_STATUS_REGISTER, ¤t_msr);
+
+   spin_lock_irqsave(&priv->lock, flags);
+   old_msr = priv->line_status;
+   spin_unlock_irqre

[PATCH v3 2/5] usb: serial: fix callback wrong process for F81232

2015-01-27 Thread Peter Hung
Our int callback will return IIR, not LSR, and bulk-in callback will return
[LSR+Data][LSR+Data], so need to rewrite it

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 82 +
 1 file changed, 39 insertions(+), 43 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index efd45a7..b372975 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -230,17 +230,33 @@ static inline int update_mctrl(struct f81232_private 
*port_priv,
 
return status;
 }
-static void f81232_update_line_status(struct usb_serial_port *port,
+
+static void f81232_iir_status(struct usb_serial_port *port,
  unsigned char *data,
  unsigned int actual_length)
 {
-   /*
-* FIXME: Update port->icount, and call
-*
-*  wake_up_interruptible(&port->port.delta_msr_wait);
-*
-*on MSR changes.
-*/
+   struct f81232_private *priv = usb_get_serial_port_data(port);
+   struct usb_device *dev = port->serial->dev;
+
+   if (!actual_length)
+   return;
+
+   switch (data[0] & 0x07) {
+   case 0x00: /* msr change */
+   dev_dbg(&dev->dev, "IIR: MSR Change: %x\n", data[0]);
+   schedule_work(&priv->int_worker);
+   break;
+
+   case 0x02: /* tx-empty */
+   break;
+
+   case 0x04: /* rx data available */
+   break;
+
+   case 0x06: /* lsr change */
+   dev_dbg(&dev->dev, "IIR: IIR: LSR Change: %x\n", data[0]);
+   break;
+   }
 }
 
 static void f81232_read_int_callback(struct urb *urb)
@@ -271,7 +287,7 @@ static void f81232_read_int_callback(struct urb *urb)
usb_serial_debug_data(&port->dev, __func__,
  urb->actual_length, urb->transfer_buffer);
 
-   f81232_update_line_status(port, data, actual_length);
+   f81232_iir_status(port, data, actual_length);
 
 exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -284,47 +300,30 @@ exit:
 static void f81232_process_read_urb(struct urb *urb)
 {
struct usb_serial_port *port = urb->context;
-   struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
char tty_flag = TTY_NORMAL;
-   unsigned long flags;
-   u8 line_status;
+   u8 line_status = 0;
int i;
 
-   /* update line status */
-   spin_lock_irqsave(&priv->lock, flags);
-   line_status = priv->line_status;
-   priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
-   spin_unlock_irqrestore(&priv->lock, flags);
 
if (!urb->actual_length)
return;
 
-   /* break takes precedence over parity, */
-   /* which takes precedence over framing errors */
-   if (line_status & UART_BREAK_ERROR)
-   tty_flag = TTY_BREAK;
-   else if (line_status & UART_PARITY_ERROR)
-   tty_flag = TTY_PARITY;
-   else if (line_status & UART_FRAME_ERROR)
-   tty_flag = TTY_FRAME;
-   dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
-
-   /* overrun is special, not associated with a char */
-   if (line_status & UART_OVERRUN_ERROR)
-   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
-   if (port->port.console && port->sysrq) {
-   for (i = 0; i < urb->actual_length; ++i)
-   if (!usb_serial_handle_sysrq_char(port, data[i]))
-   tty_insert_flip_char(&port->port, data[i],
-   tty_flag);
-   } else {
-   tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
-   urb->actual_length);
+   if (urb->actual_length >= 2) {
+
+   for (i = 0 ; i < urb->actual_length ; i += 2) {
+   line_status |= data[i+0];
+   tty_insert_flip_string_fixed_flag(&port->port,
+   &data[i+1], tty_flag, 1);
+   }
+
+   if (unlikely(line_status & UART_OVERRUN_ERROR))
+   tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
+
+   tty_flip_buffer_push(&port->port);
}
 
-   tty_flip_buffer_push(&port->port);
+
 }
 
 static int set_control_lines(struct usb_device *dev, u8 value)
@@ -456,9 +455,6 @@ static int f81232_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
 }
 
-
-
-
 static void f81232_int_work_wq(struct work_struct *work)
 {
struct f81232_private *priv =
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 3/5] usb: serial: implement function for F81232

2015-01-27 Thread Peter Hung
This patch implement the following function:
set_termios, tiocmset, tiocmget, dtr_rts

Signed-off-by: Peter Hung 
---
 drivers/usb/serial/f81232.c | 103 
 1 file changed, 84 insertions(+), 19 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index b372975..9a54f56 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -346,27 +346,99 @@ static void f81232_break_ctl(struct tty_struct *tty, int 
break_state)
 static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
 {
-   /* FIXME - Stubbed out for now */
+   u16 divisor;
+   u16 new_lcr = 0;
+   int status;
+   struct ktermios *termios = &tty->termios;
+   struct usb_device *dev = port->serial->dev;
+   unsigned int cflag = termios->c_cflag;
 
-   /* Don't change anything if nothing has changed */
-   if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
-   return;
+   divisor = calc_baud_divisor(tty_get_baud_rate(tty));
+
+   status = f81232_set_register(dev, LINE_CONTROL_REGISTER,
+UART_LCR_DLAB); /* DLAB */
+
+   status = f81232_set_register(dev, RECEIVE_BUFFER_REGISTER,
+divisor & 0x00ff); /* low */
+
+   status = f81232_set_register(dev, INTERRUPT_ENABLE_REGISTER,
+(divisor & 0xff00) >> 8); /* high */
+
+   status = f81232_set_register(dev, LINE_CONTROL_REGISTER, 0x00);
+
+
+   if (cflag & PARENB) {
+   if (cflag & PARODD)
+   new_lcr |= UART_LCR_PARITY; /* odd */
+   else
+   new_lcr |= SERIAL_EVEN_PARITY; /* even */
+   }
+
+   if (cflag & CSTOPB)
+   new_lcr |= UART_LCR_STOP;
+   else
+   new_lcr &= ~UART_LCR_STOP;
+
+   switch (cflag & CSIZE) {
+   case CS5:
+   new_lcr |= UART_LCR_WLEN5;
+   break;
+   case CS6:
+   new_lcr |= UART_LCR_WLEN6;
+   break;
+   case CS7:
+   new_lcr |= UART_LCR_WLEN7;
+   break;
+   default:
+   case CS8:
+   new_lcr |= UART_LCR_WLEN8;
+   break;
+   }
+
+   status |= f81232_set_register(dev, LINE_CONTROL_REGISTER, new_lcr);
+
+   status |= f81232_set_register(dev, FIFO_CONTROL_REGISTER,
+ 0x87); /* fifo, trigger8 */
+   status |= f81232_set_register(dev,
+ INTERRUPT_ENABLE_REGISTER, 0xf); /* IER */
+
+   if (status < 0)
+   dev_err(&port->dev, "LINE_CONTROL_REGISTER set error: %d\n",
+   status);
 
-   /* Do the real work here... */
-   if (old_termios)
-   tty_termios_copy_hw(&tty->termios, old_termios);
 }
 
 static int f81232_tiocmget(struct tty_struct *tty)
 {
-   /* FIXME - Stubbed out for now */
-   return 0;
+   int r;
+   struct usb_serial_port *port = tty->driver_data;
+   struct f81232_private *port_priv = usb_get_serial_port_data(port);
+   unsigned long flags;
+   u8 mcr, msr;
+
+   spin_lock_irqsave(&port_priv->lock, flags);
+   mcr = port_priv->line_control;
+   msr = port_priv->line_status;
+   spin_unlock_irqrestore(&port_priv->lock, flags);
+
+   r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) |
+   (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) |
+   (msr & UART_MSR_CTS ? TIOCM_CTS : 0) |
+   (msr & UART_MSR_DCD ? TIOCM_CAR : 0) |
+   (msr & UART_MSR_RI ? TIOCM_RI : 0) |
+   (msr & UART_MSR_DSR ? TIOCM_DSR : 0);
+
+   return r;
 }
 
 static int f81232_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
 {
-   /* FIXME - Stubbed out for now */
+   struct usb_serial_port *port = tty->driver_data;
+   struct f81232_private *port_priv =
+   usb_get_serial_port_data(port);
+
+   update_mctrl(port_priv, set, clear);
return 0;
 }
 
@@ -403,18 +475,11 @@ static void f81232_close(struct usb_serial_port *port)
 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 {
struct f81232_private *priv = usb_get_serial_port_data(port);
-   unsigned long flags;
-   u8 control;
 
-   spin_lock_irqsave(&priv->lock, flags);
-   /* Change DTR and RTS */
if (on)
-   priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
+   update_mctrl(priv, TIOCM_DTR | TIOCM_RTS, 0);
else
-   priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
-   control = priv->line_control;
-   spin_unlock_irqrestore(&priv->lock, flags);
-   se

  1   2   >