From: Stephane Grosjean <s.grosjean@peak-system.com>
To: Sebastian Haas <dev@sebastianhaas.info>
Cc: linux-can@vger.kernel.org
Subject: Re: "[PATCH] Add support for PEAK-System GmbH CAN USB adapters (v2) "
Date: Mon, 19 Dec 2011 18:03:34 +0100 [thread overview]
Message-ID: <1324314214625714500@peak-system.com> (raw)
In-Reply-To: <4EEC9674.2010307@sebastianhaas.info>
Le Sam, 12/17/2011 02:17 PM, @{sender } a écrit:
> Hi,
>
Hi,
> some annotations also from me. ;-)
Many thanks for these.
> Since Marc already did the coding
> style nitpicking I've tried to focus on logical stuff. I hope it is helpful.
>
> Cheers,
> Sebastian
>
My responses and explanations below. I'm working on a new version which should take into account a lot (all?) of your comments.
> Am 16.12.2011 11:19, schrieb s.grosjean@peak-system.com:
> > +static int pcan_usb_wait_response(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
> > +{
> > + int actual_length;
> > + struct pcan_usb_parameter cmd;
> > + int err;
> > +
> > + /* usb device unregistered? */
> > + if (!(dev->state& PCAN_USB_STATE_CONNECTED)) return 0;
> > +
> > + /* first, send command */
> > + err = pcan_usb_send_command(dev, f, n, NULL);
> > + if (err) {
> > + return err;
> > + }
> > +
> > + cmd.function = f;
> > + cmd.number = n;
> > + memset(&cmd.parameters[0], '\0', PCAN_USB_PARAMETER_LEN);
> > +
> > + /* then, wait for the response */
> > + mdelay(5);
> A delay to wait for a response? What happens if the device takes a
> little bit longer. This looks to be not really robust.
>
Historical reason I mean... Seems working without the mdelay(), so I'll remove it.
> > + err = usb_bulk_msg(dev->udev,
> > + usb_rcvbulkpipe(dev->udev, PCAN_USB_EP_CMDIN),
> > + &cmd, sizeof(struct pcan_usb_parameter),
> > + &actual_length, PCAN_USB_COMMAND_TIMEOUT);
> > + if (err)
> > + netdev_err(dev->netdev,
> > + "waiting response function=0x%x number=0x%x failure: %d\n",
> > + f, n, err);
> > + else if (p) memcpy(p,&cmd.parameters[0], PCAN_USB_PARAMETER_LEN);
> > +
> > + return err;
> > +}
> > +
> > +
> > +/*
> > + * Start interface
> > + */
> > +static int peak_usb_start(struct peak_usb_device *dev)
> > +{
> > + struct net_device *netdev = dev->netdev;
> > + int err, i;
> > +
> > + for (i = 0; i< PCAN_USB_MAX_RX_URBS; i++) {
> > + struct urb *urb = NULL;
> > + u8 *buf = NULL;
> > +
> > + /* create a URB, and a buffer for it, to receive usb messages */
> > + urb = usb_alloc_urb(0, GFP_KERNEL);
> > + if (!urb) {
> > + netdev_err(netdev, "No memory left for URBs\n");
> > + return -ENOMEM;
> > + }
> > +
> > + buf = usb_alloc_coherent(dev->udev, dev->adapter->rx_buffer_size,
> > + GFP_KERNEL,&urb->transfer_dma);
> > + if (!buf) {
> > + netdev_err(netdev, "No memory left for USB buffer\n");
> > + usb_free_urb(urb);
> > + return -ENOMEM;
> > + }
> > +
> > + usb_fill_bulk_urb(urb, dev->udev,
> > + usb_rcvbulkpipe(dev->udev, dev->ep_msg_in),
> > + buf, dev->adapter->rx_buffer_size,
> > + peak_usb_read_bulk_callback, dev);
> > + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> > + usb_anchor_urb(urb,&dev->rx_submitted);
> > +
> > + err = usb_submit_urb(urb, GFP_KERNEL);
> > + if (err) {
> > + if (err == -ENODEV)
> > + netif_device_detach(dev->netdev);
> > +
> > + usb_unanchor_urb(urb);
> > + usb_free_coherent(dev->udev, dev->adapter->rx_buffer_size, buf,
> > + urb->transfer_dma);
> How about the URB?
Seems you're right, "usb_free_urb()" is missing here... (Please have a look to ems_usb.c too)
> > + break;
> > + }
> > +
> > + /* Drop reference, USB core will take care of freeing it */
> > + usb_free_urb(urb);
> > + }
> > +
> > + /* Did we submit any URBs */
> > + if (i == 0) {
> > + netdev_warn(netdev, "couldn't setup read URBs\n");
> > + return err;
> > + }
> > +
> > + /* Warn if we've couldn't transmit all the URBs */
> > + if (i< PCAN_USB_MAX_RX_URBS)
> > + netdev_warn(netdev, "rx performance may be slow\n");
> > +
> > + /* Pre-alloc tx buffers and corresponding urbs */
> > + for (i = 0; i< PCAN_USB_MAX_TX_URBS; i++) {
> > + struct peak_tx_urb_context *context;
> > + struct urb *urb = NULL;
> > + u8 *buf = NULL;
> > +
> > + /* create a URB, and a buffer for it, to trsmit usb messages */
> > + urb = usb_alloc_urb(0, GFP_KERNEL);
> > + if (!urb) {
> > + netdev_err(netdev, "No memory left for URBs\n");
> > + return -ENOMEM;
> What happens with the URBs and buffers allocated before?
I changed that in the two _RX/_TX loops: if urb or buffer allocation fails, break the loop after warning into logs.
Next, check loop variable against 0 and PCAN_USB_MAX_xX_URBS: returns error if 0, warns about slow path but continue if lower than its max.
> > + }
> > +
> > + buf = usb_alloc_coherent(dev->udev, dev->adapter->tx_buffer_size,
> > + GFP_KERNEL,&urb->transfer_dma);
> > + if (!buf) {
> > + netdev_err(netdev, "No memory left for USB buffer\n");
> > + usb_free_urb(urb);
> > + return -ENOMEM;
> Dito.
Ok.
> > + }
> > +
> > + context =&dev->tx_contexts[i];
> > + context->dev = dev;
> > + context->urb = urb;
> > +
> > + usb_fill_bulk_urb(urb, dev->udev,
> > + usb_sndbulkpipe(dev->udev, dev->ep_msg_out),
> > + buf, dev->adapter->tx_buffer_size,
> > + peak_usb_write_bulk_callback, context);
> > + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> > + }
> > +
> > + /* Warn if we've couldn't transmit all the URBs */
> > + if (i< PCAN_USB_MAX_TX_URBS)
> This will never happen since the loop above will always return from this
> function in error case (return -ENOMEM).
>
Ok, now this could happen ;-)
> > + netdev_warn(netdev, "tx performance may be slow\n");
> > +
> > + if (dev->adapter->device_start) {
> > + err = dev->adapter->device_start(dev);
> > + if (err)
> > + goto failed;
> > + }
> > +
> > + /* can set bus on now */
> > + if (dev->adapter->device_set_bus) {
> > + err = dev->adapter->device_set_bus(dev, 1);
> > + if (err)
> > + goto failed;
> > + }
> > +
> > + dev->can.state = CAN_STATE_ERROR_ACTIVE;
> > +
> > + return 0;
> > +
> > +failed:
> > + if (err == -ENODEV)
> > + netif_device_detach(dev->netdev);
> > +
> > + netdev_warn(netdev, "couldn't submit control: %d\n", err);
> > +
> > + return err;
> > +}
> > +
> > +
> > +static int peak_usb_ndo_open(struct net_device *netdev)
> > +{
> > + struct peak_usb_device *dev = netdev_priv(netdev);
> > + int err;
> > +
> > + /* common open */
> > + err = open_candev(netdev);
> > + if (err)
> > + return err;
> > +
> > + /* finally start device */
> > + err = peak_usb_start(dev);
> > + if (err) {
> > + if (err == -ENODEV)
> > + netif_device_detach(dev->netdev);
> This is already done in peak_usb_start() on -ENODEV.
Ok (Great!) That's right! Think about changing ems_usb.c too.
> > +
> > + netdev_warn(netdev, "couldn't start device: %d\n", err);
> > +
> > + close_candev(netdev);
> > +
> > + return err;
> > + }
> > +
> > + dev->open_time = jiffies;
> > +
> > + netif_start_queue(netdev);
> > +
> > + return 0;
> > +}
> > +
> > +static int peak_usb_set_bittiming(struct net_device *netdev)
> > +{
> > + struct peak_usb_device *dev = netdev_priv(netdev);
> > + struct can_bittiming *bt =&dev->can.bittiming;
> > + int err;
> > +
> > + netdev_info(netdev, "set bitrate %u Kbps [sam=%d, phase_seg2=%d phase_seg1=%d prop_seg=%d sjw=%d brp=%d] ",
> > + bt->bitrate, bt->sample_point, bt->phase_seg2, bt->phase_seg1, bt->prop_seg, bt->sjw, bt->brp);
> > +
> > + if (dev->adapter->device_set_bittiming)
> > + err = dev->adapter->device_set_bittiming(dev, bt);
> > +
> > + else {
> > + printk("not supported");
> Use e.g. dev_warn or whatever.
Not sure: this "printk()" occurs next to above "netdev_info()" which format string doesn't end with any trailing '\n'
> > + err = 0;
> > + }
> > +
> > + if (err)
> > + printk(" failure (err %d)", err);
> > + printk("\n");
> > +
> > + return err;
> I would generally recommend to fix up the whole function. Dedicated err
> variable looks a bit too much cause it is only used to print error value
> for dev_set_bittiming.
... because of nested printk() (see pcan_usb_set_bittiming() and pcan_usb_pro_set_bittiming() functions in their resp. source files), I'm obliged to follow the sequence of that code, except if having a local variable for the handling of dev_set_bittiming() status is worse than several calls to printk("\n")...
> > +}
> > +
> > +static int pcan_usb_pro_wait_response(struct peak_usb_device *dev,
> > + struct pcan_usb_pro_msg_t *pum)
> > +{
> > + u8 req_data_type, req_channel;
> > + int actual_length;
> > + int i, err = 0;
> > +
> > + /* usb device unregistered? */
> > + if (!(dev->state& PCAN_USB_STATE_CONNECTED)) return 0;
> > +
> > + /* first, keep in memory the request type and the eventual channel */
> > + /* to filter received message */
> > + req_data_type = pum->u.rec_buffer[4];
> > + req_channel = pum->u.rec_buffer[5];
> > +
> > + /* then, clear number of records to be sure to receive a real response */
> > + /* from the device */
> > + *pum->u.rec_counter = 0;
> > + mdelay(5);
> I wonder if this delay is really necessary as usb_bulk_msg is waits a
> finite time to finish.
>
I removed it, then checked that it wasn't, thanks!
> > + for (i = 0; !err&& i< PCAN_USBPRO_RSP_SUBMIT_MAX; i++) {
> > + struct pcan_usb_pro_msg_t rsp;
> > + u32 r, rec_counter;
> > + u8 *pc;
> > +
> > + err = usb_bulk_msg(dev->udev,
> > + usb_rcvbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDIN),
> > + &pum->u.rec_buffer[0], pum->rec_buffer_len,
> > + &actual_length, PCAN_USBPRO_COMMAND_TIMEOUT);
> > + if (err) {
> > + netdev_err(dev->netdev, "waiting response failure: %d\n", err);
> > + break;
> > + }
> > +
> > + if (actual_length == 0) {
> > + continue;
> > + }
> > +
> > + if (actual_length< PCAN_USB_PRO_MSG_HEADER_LEN) {
> > + netdev_err(dev->netdev, "got abnormal too small response (len=%d)\n",
> > + actual_length);
> > + err = -EBADMSG;
> > + break;
> > + }
> > +
> > + pc = pcan_usb_pro_msg_init(&rsp,&pum->u.rec_buffer[0], actual_length);
> > +
> > + rec_counter = le32_to_cpu(*rsp.u.rec_counter);
> > +
> > + for (r = 0; r< rec_counter; r++) {
> > + union pcan_usb_pro_rec_t *pr = (union pcan_usb_pro_rec_t *)pc;
> > + int rec_size = pcan_usb_pro_sizeof_rec(pr->data_type);
> > + if (rec_size<= 0) {
> > + netdev_err(dev->netdev, "got unprocessed record in msg\n");
> > + dump_mem("received response msg",
> > + &pum->u.rec_buffer[0], actual_length);
> > + err = -EBADMSG;
> > + break;
> > + }
> > +
> > + /* check if the response corresponds to the request */
> > + if (pr->data_type != req_data_type) {
> Empty statement.
> > + }
> > +
> > + /* check if the channel in the response corresponds to the request */
> > + else if ((req_channel != 0xff)&& (pr->bus_activity.channel != req_channel)) {
> Dito.
> > + }
> > +
> > + /* got the response */
> > + else return 0;
> Optimize the if/else if/else statement to also ge rid of the empty
> statements.
Sorry for that... These empty statements come from an unifdef pass which removes some DEBUG #ifdef/#endif... Now, the if statement has been included into the block or #ifdef/#endif have been removed.
> > +
> > + /* otherwise, go on with next record in message */
> > + pc += rec_size;
> > + }
> > +
> > + if (r>= rec_counter) {
> Empty statement. Remove it.
See above.
> > + }
> > + }
> > +
> > + return (i>= PCAN_USBPRO_RSP_SUBMIT_MAX) ? -ERANGE : err;
> > +}
> > +
> > +static int pcan_usb_pro_request(struct peak_usb_device *dev, int req_id, int req_value, void *req_addr, int req_size)
> > +{
> > + int err;
> > + u8 req_type;
> > + unsigned int p;
> > +
> > + /* usb device unregistered? */
> > + if (!(dev->state& PCAN_USB_STATE_CONNECTED)) return 0;
> > +
> > + memset(req_addr, '\0', req_size);
> > +
> > + req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER;
> > + switch (req_id) {
> > + case USB_VENDOR_REQUEST_FKT:
> > + /* Host to device */
> > + p = usb_sndctrlpipe(dev->udev, 0);
> > + break;
> > +
> > + case USB_VENDOR_REQUEST_INFO:
> > + default:
> > + /* Device to host */
> > + p = usb_rcvctrlpipe(dev->udev, 0);
> > + req_type |= USB_DIR_IN;
> Missing break.
Ok.
> > + }
> > +
> > + err = usb_control_msg(dev->udev,
> > + p,
> > + req_id,
> > + req_type,
> > + req_value,
> > + 0, req_addr, req_size,
> > + 2*USB_CTRL_GET_TIMEOUT);
> > + if (err< 0)
> > + netdev_info(dev->netdev,
> > + "unable to request usb[type=%d value=%d] err=%d\n",
> > + req_id, req_value, err);
> > + else {
> > + //dump_mem("request content", req_addr, req_size);
> > + err = 0;
> > + }
> > +
> > + return err;
> > +}
> > +
> > +
> > +/*
> > + * called when driver module is being unloaded:
> > + *
> > + * rmmod when plugged => module_exit => device_exit, then
> > + * usb_deregister(), then
> > + * device_stop, then
> > + * module_disconnect => device_free
> > + * rmmod but unplugged => module_exit
> > + * unplug => module_disconnect => device_free
> > + *
> > + * (last change to send something on usb)
> > + */
> > +static void pcan_usb_pro_exit(struct peak_usb_device *dev)
> > +{
> > + struct pcan_usb_pro_device *pdev = (struct pcan_usb_pro_device *)dev;
> > +
> > + /* when rmmod called before unplug and ifconfig down, MUST reset things */
> > + /* before leaving */
> > + if (dev->can.state != CAN_STATE_STOPPED) {
> > +
> > + /* set bus off on the corresponding channel */
> > + pcan_usb_pro_set_bus(dev, 0);
> > + }
> > +
> > + /* if channel #0 (only) => tell PCAN-USB-PRO the can driver is being */
> > + /* unloaded */
> > + if (dev->ctrl_index == 0) {
> > +
> > + /* turn off calibration message if any device were opened */
> > + if (pdev->usb_if->dev_opened_count> 0)
> > + pcan_usb_pro_set_calibration_msgs(dev, 0);
> > +
> > + /* tell the PCAN-USB-PRO device that drive is being unloaded */
> > + pcan_usb_pro_driver_loaded(dev, 0, 0);
> > +
> > + /* this device needs also to be resetted when driver is unloaded */
> > + /* TODO hangs when rmmod */
> Then fix it. ;-)
... or remove the comment ;-))
So, comment is in fact to be removed since the issue didn't exist at all.
> > + //if (dev->udev)
> > + // usb_reset_device(dev->udev);
> > + }
> > +}
> > +
> --
> To unsubscribe from this list: send the line "unsubscribe linux-can" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
PEAK-System Technik GmbH, Otto-Roehm-Strasse 69, D-64293 Darmstadt
Geschaeftsleitung: A.Gach/U.Wilhelm, HRB 9183 Darmstadt, Ust.IdNr.:DE 202 220 078
St.Nr.:007/241/13586 FA Darmstadt, WEE-Reg.-Nr.: DE39305391
Tel.:+49 (0)6151 8173-20 - Fax:+49 (0)6151 8173-29
E-mail: info@peak-system.com - http://www.peak-system.com
next prev parent reply other threads:[~2011-12-19 17:09 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-16 10:19 "[PATCH] Add support for PEAK-System GmbH CAN USB adapters (v2) " s.grosjean
2011-12-16 11:34 ` Wolfgang Grandegger
2011-12-16 12:41 ` Marc Kleine-Budde
2011-12-20 12:10 ` Grosjean Stephane
2011-12-20 15:57 ` Wolfgang Grandegger
2011-12-20 20:50 ` Marc Kleine-Budde
2011-12-17 13:17 ` Sebastian Haas
2011-12-19 17:03 ` Stephane Grosjean [this message]
2011-12-21 9:33 ` Wolfgang Grandegger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1324314214625714500@peak-system.com \
--to=s.grosjean@peak-system.com \
--cc=dev@sebastianhaas.info \
--cc=linux-can@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).