root/drivers/staging/wusbcore/wa-nep.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wa_notif_dispatch
  2. wa_nep_queue
  3. wa_nep_cb
  4. wa_nep_create
  5. wa_nep_destroy

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
   4  * Notification EndPoint support
   5  *
   6  * Copyright (C) 2006 Intel Corporation
   7  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
   8  *
   9  * This part takes care of getting the notification from the hw
  10  * only and dispatching through wusbwad into
  11  * wa_notif_dispatch. Handling is done there.
  12  *
  13  * WA notifications are limited in size; most of them are three or
  14  * four bytes long, and the longest is the HWA Device Notification,
  15  * which would not exceed 38 bytes (DNs are limited in payload to 32
  16  * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA
  17  * header (WUSB1.0[8.5.4.2]).
  18  *
  19  * It is not clear if more than one Device Notification can be packed
  20  * in a HWA Notification, I assume no because of the wording in
  21  * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could
  22  * get is 256 bytes (as the bLength field is a byte).
  23  *
  24  * So what we do is we have this buffer and read into it; when a
  25  * notification arrives we schedule work to a specific, single thread
  26  * workqueue (so notifications are serialized) and copy the
  27  * notification data. After scheduling the work, we rearm the read from
  28  * the notification endpoint.
  29  *
  30  * Entry points here are:
  31  *
  32  * wa_nep_[create|destroy]()   To initialize/release this subsystem
  33  *
  34  * wa_nep_cb()                 Callback for the notification
  35  *                                endpoint; when data is ready, this
  36  *                                does the dispatching.
  37  */
  38 #include <linux/workqueue.h>
  39 #include <linux/ctype.h>
  40 #include <linux/slab.h>
  41 
  42 #include "wa-hc.h"
  43 #include "wusbhc.h"
  44 
  45 /* Structure for queueing notifications to the workqueue */
  46 struct wa_notif_work {
  47         struct work_struct work;
  48         struct wahc *wa;
  49         size_t size;
  50         u8 data[];
  51 };
  52 
  53 /*
  54  * Process incoming notifications from the WA's Notification EndPoint
  55  * [the wuswad daemon, basically]
  56  *
  57  * @_nw:        Pointer to a descriptor which has the pointer to the
  58  *              @wa, the size of the buffer and the work queue
  59  *              structure (so we can free all when done).
  60  * @returns     0 if ok, < 0 errno code on error.
  61  *
  62  * All notifications follow the same format; they need to start with a
  63  * 'struct wa_notif_hdr' header, so it is easy to parse through
  64  * them. We just break the buffer in individual notifications (the
  65  * standard doesn't say if it can be done or is forbidden, so we are
  66  * cautious) and dispatch each.
  67  *
  68  * So the handling layers are is:
  69  *
  70  *   WA specific notification (from NEP)
  71  *      Device Notification Received -> wa_handle_notif_dn()
  72  *        WUSB Device notification generic handling
  73  *      BPST Adjustment -> wa_handle_notif_bpst_adj()
  74  *      ... -> ...
  75  *
  76  * @wa has to be referenced
  77  */
  78 static void wa_notif_dispatch(struct work_struct *ws)
  79 {
  80         void *itr;
  81         u8 missing = 0;
  82         struct wa_notif_work *nw = container_of(ws, struct wa_notif_work,
  83                                                 work);
  84         struct wahc *wa = nw->wa;
  85         struct wa_notif_hdr *notif_hdr;
  86         size_t size;
  87 
  88         struct device *dev = &wa->usb_iface->dev;
  89 
  90 #if 0
  91         /* FIXME: need to check for this??? */
  92         if (usb_hcd->state == HC_STATE_QUIESCING)       /* Going down? */
  93                 goto out;                               /* screw it */
  94 #endif
  95         atomic_dec(&wa->notifs_queued);         /* Throttling ctl */
  96         size = nw->size;
  97         itr = nw->data;
  98 
  99         while (size) {
 100                 if (size < sizeof(*notif_hdr)) {
 101                         missing = sizeof(*notif_hdr) - size;
 102                         goto exhausted_buffer;
 103                 }
 104                 notif_hdr = itr;
 105                 if (size < notif_hdr->bLength)
 106                         goto exhausted_buffer;
 107                 itr += notif_hdr->bLength;
 108                 size -= notif_hdr->bLength;
 109                 /* Dispatch the notification [don't use itr or size!] */
 110                 switch (notif_hdr->bNotifyType) {
 111                 case HWA_NOTIF_DN: {
 112                         struct hwa_notif_dn *hwa_dn;
 113                         hwa_dn = container_of(notif_hdr, struct hwa_notif_dn,
 114                                               hdr);
 115                         wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr,
 116                                          hwa_dn->dndata,
 117                                          notif_hdr->bLength - sizeof(*hwa_dn));
 118                         break;
 119                 }
 120                 case WA_NOTIF_TRANSFER:
 121                         wa_handle_notif_xfer(wa, notif_hdr);
 122                         break;
 123                 case HWA_NOTIF_BPST_ADJ:
 124                         break; /* no action needed for BPST ADJ. */
 125                 case DWA_NOTIF_RWAKE:
 126                 case DWA_NOTIF_PORTSTATUS:
 127                         /* FIXME: unimplemented WA NOTIFs */
 128                         /* fallthru */
 129                 default:
 130                         dev_err(dev, "HWA: unknown notification 0x%x, "
 131                                 "%zu bytes; discarding\n",
 132                                 notif_hdr->bNotifyType,
 133                                 (size_t)notif_hdr->bLength);
 134                         break;
 135                 }
 136         }
 137 out:
 138         wa_put(wa);
 139         kfree(nw);
 140         return;
 141 
 142         /* THIS SHOULD NOT HAPPEN
 143          *
 144          * Buffer exahusted with partial data remaining; just warn and
 145          * discard the data, as this should not happen.
 146          */
 147 exhausted_buffer:
 148         dev_warn(dev, "HWA: device sent short notification, "
 149                  "%d bytes missing; discarding %d bytes.\n",
 150                  missing, (int)size);
 151         goto out;
 152 }
 153 
 154 /*
 155  * Deliver incoming WA notifications to the wusbwa workqueue
 156  *
 157  * @wa: Pointer the Wire Adapter Controller Data Streaming
 158  *              instance (part of an 'struct usb_hcd').
 159  * @size:       Size of the received buffer
 160  * @returns     0 if ok, < 0 errno code on error.
 161  *
 162  * The input buffer is @wa->nep_buffer, with @size bytes
 163  * (guaranteed to fit in the allocated space,
 164  * @wa->nep_buffer_size).
 165  */
 166 static int wa_nep_queue(struct wahc *wa, size_t size)
 167 {
 168         int result = 0;
 169         struct device *dev = &wa->usb_iface->dev;
 170         struct wa_notif_work *nw;
 171 
 172         /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */
 173         BUG_ON(size > wa->nep_buffer_size);
 174         if (size == 0)
 175                 goto out;
 176         if (atomic_read(&wa->notifs_queued) > 200) {
 177                 if (printk_ratelimit())
 178                         dev_err(dev, "Too many notifications queued, "
 179                                 "throttling back\n");
 180                 goto out;
 181         }
 182         nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC);
 183         if (nw == NULL) {
 184                 if (printk_ratelimit())
 185                         dev_err(dev, "No memory to queue notification\n");
 186                 result = -ENOMEM;
 187                 goto out;
 188         }
 189         INIT_WORK(&nw->work, wa_notif_dispatch);
 190         nw->wa = wa_get(wa);
 191         nw->size = size;
 192         memcpy(nw->data, wa->nep_buffer, size);
 193         atomic_inc(&wa->notifs_queued);         /* Throttling ctl */
 194         queue_work(wusbd, &nw->work);
 195 out:
 196         /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */
 197         return result;
 198 }
 199 
 200 /*
 201  * Callback for the notification event endpoint
 202  *
 203  * Check's that everything is fine and then passes the data to be
 204  * queued to the workqueue.
 205  */
 206 static void wa_nep_cb(struct urb *urb)
 207 {
 208         int result;
 209         struct wahc *wa = urb->context;
 210         struct device *dev = &wa->usb_iface->dev;
 211 
 212         switch (result = urb->status) {
 213         case 0:
 214                 result = wa_nep_queue(wa, urb->actual_length);
 215                 if (result < 0)
 216                         dev_err(dev, "NEP: unable to process notification(s): "
 217                                 "%d\n", result);
 218                 break;
 219         case -ECONNRESET:       /* Not an error, but a controlled situation; */
 220         case -ENOENT:           /* (we killed the URB)...so, no broadcast */
 221         case -ESHUTDOWN:
 222                 dev_dbg(dev, "NEP: going down %d\n", urb->status);
 223                 goto out;
 224         default:        /* On general errors, we retry unless it gets ugly */
 225                 if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
 226                             EDC_ERROR_TIMEFRAME)) {
 227                         dev_err(dev, "NEP: URB max acceptable errors "
 228                                 "exceeded, resetting device\n");
 229                         wa_reset_all(wa);
 230                         goto out;
 231                 }
 232                 dev_err(dev, "NEP: URB error %d\n", urb->status);
 233         }
 234         result = wa_nep_arm(wa, GFP_ATOMIC);
 235         if (result < 0) {
 236                 dev_err(dev, "NEP: cannot submit URB: %d\n", result);
 237                 wa_reset_all(wa);
 238         }
 239 out:
 240         return;
 241 }
 242 
 243 /*
 244  * Initialize @wa's notification and event's endpoint stuff
 245  *
 246  * This includes the allocating the read buffer, the context ID
 247  * allocation bitmap, the URB and submitting the URB.
 248  */
 249 int wa_nep_create(struct wahc *wa, struct usb_interface *iface)
 250 {
 251         int result;
 252         struct usb_endpoint_descriptor *epd;
 253         struct usb_device *usb_dev = interface_to_usbdev(iface);
 254         struct device *dev = &iface->dev;
 255 
 256         edc_init(&wa->nep_edc);
 257         epd = &iface->cur_altsetting->endpoint[0].desc;
 258         wa->nep_buffer_size = 1024;
 259         wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL);
 260         if (!wa->nep_buffer)
 261                 goto error_nep_buffer;
 262         wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL);
 263         if (wa->nep_urb == NULL)
 264                 goto error_urb_alloc;
 265         usb_fill_int_urb(wa->nep_urb, usb_dev,
 266                          usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
 267                          wa->nep_buffer, wa->nep_buffer_size,
 268                          wa_nep_cb, wa, epd->bInterval);
 269         result = wa_nep_arm(wa, GFP_KERNEL);
 270         if (result < 0) {
 271                 dev_err(dev, "Cannot submit notification URB: %d\n", result);
 272                 goto error_nep_arm;
 273         }
 274         return 0;
 275 
 276 error_nep_arm:
 277         usb_free_urb(wa->nep_urb);
 278 error_urb_alloc:
 279         kfree(wa->nep_buffer);
 280 error_nep_buffer:
 281         return -ENOMEM;
 282 }
 283 
 284 void wa_nep_destroy(struct wahc *wa)
 285 {
 286         wa_nep_disarm(wa);
 287         usb_free_urb(wa->nep_urb);
 288         kfree(wa->nep_buffer);
 289 }

/* [<][>][^][v][top][bottom][index][help] */