lkml.org 
[lkml]   [2022]   [Sep]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
SubjectRe: [PATCH 1/2] usb: serial: add support for CH348
From
On 06.09.22 10:29, Corentin Labbe wrote:
> The CH348 is an USB octo port serial adapter.
> This patch adds support for it.

Hi,

thanks for the driver. Unfortunately there are a few issues.
Comments inline.

Regards
Oliver

> +
> +#define CH348_CTO_D 0x01
> +#define CH348_CTO_R 0x02
> +
> +#define CH348_CTI_C 0x10
> +#define CH348_CTI_DSR 0x20
> +#define CH348_CTI_R 0x40
> +#define CH348_CTI_DCD 0x80
> +
> +#define CH348_LO 0x02
> +#define CH348_LP 0x04
> +#define CH348_LF 0x08
> +#define CH348_LB 0x10
> +
> +#define CMD_W_R 0xC0
> +#define CMD_W_BR 0x80
> +
> +#define CMD_WB_E 0x90
> +#define CMD_RB_E 0xC0
> +
> +#define M_NOR 0x00
> +#define M_HF 0x03
> +
> +#define R_MOD 0x97
> +#define R_IO_D 0x98
> +#define R_IO_O 0x99
> +#define R_IO_I 0x9b
> +#define R_TM_O 0x9c
> +#define R_INIT 0xa1
> +
> +#define R_C1 0x01
> +#define R_C2 0x02
> +#define R_C4 0x04
> +#define R_C5 0x06
> +
> +#define R_II_B1 0x06
> +#define R_II_B2 0x02
> +#define R_II_B3 0x00
> +
> +#define CH348_RX_PORTNUM_OFF 0
> +#define CH348_RX_LENGTH_OFF 1
> +#define CH348_RX_DATA_OFF 2
> +
> +#define CH348_RX_PORT_CHUNK_LENGTH 32
> +#define CH348_RX_PORT_MAX_LENGTH 30
> +
> +#define CH348_TX_PORTNUM_OFF 0
> +#define CH348_TX_LENGTH0_OFF 1
> +#define CH348_TX_LENGTH1_OFF 2
> +#define CH348_TX_DATA_OFF 3

This is, well, horrible. If the device uses a defined package
to transmit data to and from the host, please define a data
structure for it.
An array of u8 and offsets defined as preprocessor constants
is not the clean way to do this.


> +/* Some values came from vendor tree, and we have no meaning for them, this
> + * function simply use them.
> + */
> +static int ch348_do_magic(struct ch348 *ch348, int portnum, u8 action, u8 reg, u8 control)
> +{
> + int ret = 0, len;
> + u8 *buffer;

This should probably also be a defined data structure.

> +static void ch348_process_read_urb(struct urb *urb)
> +{
> + struct usb_serial_port *port = urb->context;
> + struct ch348 *ch348 = usb_get_serial_data(port->serial);
> + u8 *buffer = urb->transfer_buffer, *end;
> + unsigned int portnum, usblen;
> +
> + if (!urb->actual_length) {
> + dev_warn(&port->dev, "%s:%d empty rx buffer\n", __func__, __LINE__);
> + return;
> + }
> +
> + end = buffer + urb->actual_length;
> +
> + for (; buffer < end; buffer += CH348_RX_PORT_CHUNK_LENGTH) {

What happens if you get a partial chunk?

> + portnum = buffer[CH348_RX_PORTNUM_OFF];
> + if (portnum >= CH348_MAXPORT) {
> + dev_warn(&port->dev, "%s:%d invalid port %d\n",
> + __func__, __LINE__, portnum);
> + break;
> + }
> +
> + usblen = buffer[CH348_RX_LENGTH_OFF];
> + if (usblen > 30) {
> + dev_warn(&port->dev, "%s:%d invalid length %d for port %d\n",
> + __func__, __LINE__, usblen, portnum);
> + break;
> + }
> +
> + port = ch348->ttyport[portnum].port;
> + tty_insert_flip_string(&port->port, &buffer[CH348_RX_DATA_OFF], usblen);
> + tty_flip_buffer_push(&port->port);
> + port->icount.rx += usblen;
> + usb_serial_debug_data(&port->dev, __func__, usblen, &buffer[CH348_RX_DATA_OFF]);
> + }
> +}
> +
> +static int ch348_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size)
> +{
> + u8 *buf = dest;
> + int count;
> +
> + count = kfifo_out_locked(&port->write_fifo, buf + CH348_TX_DATA_OFF,
> + size - CH348_TX_DATA_OFF,
> + &port->lock);
> +
> + buf[CH348_TX_PORTNUM_OFF] = port->port_number;
> + buf[CH348_TX_LENGTH0_OFF] = count;
> + buf[CH348_TX_LENGTH1_OFF] = count >> 8;

We have macros for this conversion.
> +static void ch348_status_read_bulk_callback(struct urb *urb)
> +{
> + struct ch348 *ch348 = urb->context;
> + u8 *data = urb->transfer_buffer;
> + unsigned int len = urb->actual_length;
> + int ret;
> +
> + switch (urb->status) {
> + case 0:
> + /* success */
> + break;
> + case -ECONNRESET:
> + case -ENOENT:
> + case -ESHUTDOWN:
> + /* this urb is terminated, clean up */
> + dev_dbg(&ch348->udev->dev, "%s - urb shutting down: %d\n",
> + __func__, urb->status);
> + return;
> + default:
> + dev_dbg(&ch348->udev->dev, "%s - nonzero urb status: %d\n",
> + __func__, urb->status);
> + goto exit;
> + }
> +
> + usb_serial_debug_data(&ch348->udev->dev, __func__, len, data);
> + ch348_update_status(ch348, data, len);
> +
> +exit:
> + ret = usb_submit_urb(urb, GFP_ATOMIC);
> + if (ret && urb->status == 0) {

Why check urb->status?
> + dev_err(&ch348->udev->dev, "%s - usb_submit_urb failed: %d\n",
> + __func__, ret);
> + }
> +}
> +
> +static int ch348_allocate_status_read(struct ch348 *ch348, struct usb_endpoint_descriptor *epd)
> +{
> + int buffer_size = usb_endpoint_maxp(epd);
> +
> + ch348->status_read_urb = usb_alloc_urb(0, GFP_KERNEL);
> + if (!ch348->status_read_urb)
> + return -ENOMEM;
> + ch348->status_read_buffer = kmalloc(buffer_size, GFP_KERNEL);
> + if (!ch348->status_read_buffer)
> + return -ENOMEM;
> +
> + usb_fill_bulk_urb(ch348->status_read_urb, ch348->udev,
> + ch348->statusrx_endpoint, ch348->status_read_buffer,
> + buffer_size, ch348_status_read_bulk_callback, ch348);
> +
> + return 0;
> +}
> +
> +static void ch348_release(struct usb_serial *serial)
> +{
> + struct ch348 *ch348 = usb_get_serial_data(serial);
> +
> + usb_kill_urb(ch348->status_read_urb);
> + usb_free_urb(ch348->status_read_urb);
> +}
> +
> +static int ch348_probe(struct usb_serial *serial, const struct usb_device_id *id)
> +{
> + struct usb_interface *data_interface;
> + struct usb_endpoint_descriptor *epcmdwrite = NULL;
> + struct usb_endpoint_descriptor *epstatusread = NULL;
> + struct usb_endpoint_descriptor *epread = NULL;
> + struct usb_endpoint_descriptor *epwrite = NULL;
> + struct usb_device *usb_dev = serial->dev;
> + struct ch348 *ch348;
> + int ret;
> +
> + data_interface = usb_ifnum_to_if(usb_dev, 0);
> +
> + epread = &data_interface->cur_altsetting->endpoint[0].desc;
> + epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
> + epstatusread = &data_interface->cur_altsetting->endpoint[2].desc;
> + epcmdwrite = &data_interface->cur_altsetting->endpoint[3].desc;

Please check that these endpoints exist.
> +
> + ch348 = devm_kzalloc(&serial->dev->dev, sizeof(*ch348), GFP_KERNEL);
> + if (!ch348)
> + return -ENOMEM;
> +
> + usb_set_serial_data(serial, ch348);
> +
> + ch348->readsize = usb_endpoint_maxp(epread);
> + ch348->writesize = usb_endpoint_maxp(epwrite);
> + ch348->udev = serial->dev;
> +
> + spin_lock_init(&ch348->status_lock);
> +
> + ch348->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
> + ch348->tx_endpoint = usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress);
> + ch348->cmdtx_endpoint = usb_sndbulkpipe(usb_dev, epcmdwrite->bEndpointAddress);
> + ch348->statusrx_endpoint = usb_rcvbulkpipe(usb_dev, epstatusread->bEndpointAddress);
> +
> + ret = ch348_allocate_status_read(ch348, epstatusread);
> + if (ret)
> + return ret;

This leaks an URB in the error case. Either fix it up here or in
ch348_allocate_status_read().

\
 
 \ /
  Last update: 2022-09-06 11:05    [W:0.043 / U:0.400 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site