Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.14-rc3 449 lines 13 kB view raw
1/* ----------------------------------------------------------------------------- 2 * Copyright (c) 2011 Ozmo Inc 3 * Released under the GNU General Public License Version 2 (GPLv2). 4 * 5 * This file implements the protocol specific parts of the USB service for a PD. 6 * ----------------------------------------------------------------------------- 7 */ 8#include <linux/module.h> 9#include <linux/timer.h> 10#include <linux/sched.h> 11#include <linux/netdevice.h> 12#include <linux/errno.h> 13#include <linux/input.h> 14#include <asm/unaligned.h> 15#include "ozdbg.h" 16#include "ozprotocol.h" 17#include "ozeltbuf.h" 18#include "ozpd.h" 19#include "ozproto.h" 20#include "ozusbif.h" 21#include "ozhcd.h" 22#include "ozusbsvc.h" 23 24#define MAX_ISOC_FIXED_DATA (253-sizeof(struct oz_isoc_fixed)) 25 26/* 27 * Context: softirq 28 */ 29static int oz_usb_submit_elt(struct oz_elt_buf *eb, struct oz_elt_info *ei, 30 struct oz_usb_ctx *usb_ctx, u8 strid, u8 isoc) 31{ 32 int ret; 33 struct oz_elt *elt = (struct oz_elt *)ei->data; 34 struct oz_app_hdr *app_hdr = (struct oz_app_hdr *)(elt+1); 35 36 elt->type = OZ_ELT_APP_DATA; 37 ei->app_id = OZ_APPID_USB; 38 ei->length = elt->length + sizeof(struct oz_elt); 39 app_hdr->app_id = OZ_APPID_USB; 40 spin_lock_bh(&eb->lock); 41 if (isoc == 0) { 42 app_hdr->elt_seq_num = usb_ctx->tx_seq_num++; 43 if (usb_ctx->tx_seq_num == 0) 44 usb_ctx->tx_seq_num = 1; 45 } 46 ret = oz_queue_elt_info(eb, isoc, strid, ei); 47 if (ret) 48 oz_elt_info_free(eb, ei); 49 spin_unlock_bh(&eb->lock); 50 return ret; 51} 52 53/* 54 * Context: softirq 55 */ 56int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type, 57 u8 index, u16 windex, int offset, int len) 58{ 59 struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; 60 struct oz_pd *pd = usb_ctx->pd; 61 struct oz_elt *elt; 62 struct oz_get_desc_req *body; 63 struct oz_elt_buf *eb = &pd->elt_buff; 64 struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); 65 66 oz_dbg(ON, " req_type = 0x%x\n", req_type); 67 oz_dbg(ON, " desc_type = 0x%x\n", desc_type); 68 oz_dbg(ON, " index = 0x%x\n", index); 69 oz_dbg(ON, " windex = 0x%x\n", windex); 70 oz_dbg(ON, " offset = 0x%x\n", offset); 71 oz_dbg(ON, " len = 0x%x\n", len); 72 if (len > 200) 73 len = 200; 74 if (ei == NULL) 75 return -1; 76 elt = (struct oz_elt *)ei->data; 77 elt->length = sizeof(struct oz_get_desc_req); 78 body = (struct oz_get_desc_req *)(elt+1); 79 body->type = OZ_GET_DESC_REQ; 80 body->req_id = req_id; 81 put_unaligned(cpu_to_le16(offset), &body->offset); 82 put_unaligned(cpu_to_le16(len), &body->size); 83 body->req_type = req_type; 84 body->desc_type = desc_type; 85 body->w_index = windex; 86 body->index = index; 87 return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); 88} 89 90/* 91 * Context: tasklet 92 */ 93static int oz_usb_set_config_req(void *hpd, u8 req_id, u8 index) 94{ 95 struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; 96 struct oz_pd *pd = usb_ctx->pd; 97 struct oz_elt *elt; 98 struct oz_elt_buf *eb = &pd->elt_buff; 99 struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); 100 struct oz_set_config_req *body; 101 102 if (ei == NULL) 103 return -1; 104 elt = (struct oz_elt *)ei->data; 105 elt->length = sizeof(struct oz_set_config_req); 106 body = (struct oz_set_config_req *)(elt+1); 107 body->type = OZ_SET_CONFIG_REQ; 108 body->req_id = req_id; 109 body->index = index; 110 return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); 111} 112 113/* 114 * Context: tasklet 115 */ 116static int oz_usb_set_interface_req(void *hpd, u8 req_id, u8 index, u8 alt) 117{ 118 struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; 119 struct oz_pd *pd = usb_ctx->pd; 120 struct oz_elt *elt; 121 struct oz_elt_buf *eb = &pd->elt_buff; 122 struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); 123 struct oz_set_interface_req *body; 124 125 if (ei == NULL) 126 return -1; 127 elt = (struct oz_elt *)ei->data; 128 elt->length = sizeof(struct oz_set_interface_req); 129 body = (struct oz_set_interface_req *)(elt+1); 130 body->type = OZ_SET_INTERFACE_REQ; 131 body->req_id = req_id; 132 body->index = index; 133 body->alternative = alt; 134 return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); 135} 136 137/* 138 * Context: tasklet 139 */ 140static int oz_usb_set_clear_feature_req(void *hpd, u8 req_id, u8 type, 141 u8 recipient, u8 index, __le16 feature) 142{ 143 struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; 144 struct oz_pd *pd = usb_ctx->pd; 145 struct oz_elt *elt; 146 struct oz_elt_buf *eb = &pd->elt_buff; 147 struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); 148 struct oz_feature_req *body; 149 150 if (ei == NULL) 151 return -1; 152 elt = (struct oz_elt *)ei->data; 153 elt->length = sizeof(struct oz_feature_req); 154 body = (struct oz_feature_req *)(elt+1); 155 body->type = type; 156 body->req_id = req_id; 157 body->recipient = recipient; 158 body->index = index; 159 put_unaligned(feature, &body->feature); 160 return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); 161} 162 163/* 164 * Context: tasklet 165 */ 166static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type, 167 u8 request, __le16 value, __le16 index, const u8 *data, int data_len) 168{ 169 struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; 170 struct oz_pd *pd = usb_ctx->pd; 171 struct oz_elt *elt; 172 struct oz_elt_buf *eb = &pd->elt_buff; 173 struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); 174 struct oz_vendor_class_req *body; 175 176 if (ei == NULL) 177 return -1; 178 elt = (struct oz_elt *)ei->data; 179 elt->length = sizeof(struct oz_vendor_class_req) - 1 + data_len; 180 body = (struct oz_vendor_class_req *)(elt+1); 181 body->type = OZ_VENDOR_CLASS_REQ; 182 body->req_id = req_id; 183 body->req_type = req_type; 184 body->request = request; 185 put_unaligned(value, &body->value); 186 put_unaligned(index, &body->index); 187 if (data_len) 188 memcpy(body->data, data, data_len); 189 return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); 190} 191 192/* 193 * Context: tasklet 194 */ 195int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup, 196 const u8 *data, int data_len) 197{ 198 unsigned wvalue = le16_to_cpu(setup->wValue); 199 unsigned windex = le16_to_cpu(setup->wIndex); 200 unsigned wlength = le16_to_cpu(setup->wLength); 201 int rc = 0; 202 203 if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 204 switch (setup->bRequest) { 205 case USB_REQ_GET_DESCRIPTOR: 206 rc = oz_usb_get_desc_req(hpd, req_id, 207 setup->bRequestType, (u8)(wvalue>>8), 208 (u8)wvalue, setup->wIndex, 0, wlength); 209 break; 210 case USB_REQ_SET_CONFIGURATION: 211 rc = oz_usb_set_config_req(hpd, req_id, (u8)wvalue); 212 break; 213 case USB_REQ_SET_INTERFACE: { 214 u8 if_num = (u8)windex; 215 u8 alt = (u8)wvalue; 216 rc = oz_usb_set_interface_req(hpd, req_id, 217 if_num, alt); 218 } 219 break; 220 case USB_REQ_SET_FEATURE: 221 rc = oz_usb_set_clear_feature_req(hpd, req_id, 222 OZ_SET_FEATURE_REQ, 223 setup->bRequestType & 0xf, (u8)windex, 224 setup->wValue); 225 break; 226 case USB_REQ_CLEAR_FEATURE: 227 rc = oz_usb_set_clear_feature_req(hpd, req_id, 228 OZ_CLEAR_FEATURE_REQ, 229 setup->bRequestType & 0xf, 230 (u8)windex, setup->wValue); 231 break; 232 } 233 } else { 234 rc = oz_usb_vendor_class_req(hpd, req_id, setup->bRequestType, 235 setup->bRequest, setup->wValue, setup->wIndex, 236 data, data_len); 237 } 238 return rc; 239} 240 241/* 242 * Context: softirq 243 */ 244int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb) 245{ 246 struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; 247 struct oz_pd *pd = usb_ctx->pd; 248 struct oz_elt_buf *eb; 249 int i; 250 int hdr_size; 251 u8 *data; 252 struct usb_iso_packet_descriptor *desc; 253 254 if (pd->mode & OZ_F_ISOC_NO_ELTS) { 255 for (i = 0; i < urb->number_of_packets; i++) { 256 u8 *data; 257 desc = &urb->iso_frame_desc[i]; 258 data = ((u8 *)urb->transfer_buffer)+desc->offset; 259 oz_send_isoc_unit(pd, ep_num, data, desc->length); 260 } 261 return 0; 262 } 263 264 hdr_size = sizeof(struct oz_isoc_fixed) - 1; 265 eb = &pd->elt_buff; 266 i = 0; 267 while (i < urb->number_of_packets) { 268 struct oz_elt_info *ei = oz_elt_info_alloc(eb); 269 struct oz_elt *elt; 270 struct oz_isoc_fixed *body; 271 int unit_count; 272 int unit_size; 273 int rem; 274 if (ei == NULL) 275 return -1; 276 rem = MAX_ISOC_FIXED_DATA; 277 elt = (struct oz_elt *)ei->data; 278 body = (struct oz_isoc_fixed *)(elt + 1); 279 body->type = OZ_USB_ENDPOINT_DATA; 280 body->endpoint = ep_num; 281 body->format = OZ_DATA_F_ISOC_FIXED; 282 unit_size = urb->iso_frame_desc[i].length; 283 body->unit_size = (u8)unit_size; 284 data = ((u8 *)(elt+1)) + hdr_size; 285 unit_count = 0; 286 while (i < urb->number_of_packets) { 287 desc = &urb->iso_frame_desc[i]; 288 if ((unit_size == desc->length) && 289 (desc->length <= rem)) { 290 memcpy(data, ((u8 *)urb->transfer_buffer) + 291 desc->offset, unit_size); 292 data += unit_size; 293 rem -= unit_size; 294 unit_count++; 295 desc->status = 0; 296 desc->actual_length = desc->length; 297 i++; 298 } else { 299 break; 300 } 301 } 302 elt->length = hdr_size + MAX_ISOC_FIXED_DATA - rem; 303 /* Store the number of units in body->frame_number for the 304 * moment. This field will be correctly determined before 305 * the element is sent. */ 306 body->frame_number = (u8)unit_count; 307 oz_usb_submit_elt(eb, ei, usb_ctx, ep_num, 308 pd->mode & OZ_F_ISOC_ANYTIME); 309 } 310 return 0; 311} 312 313/* 314 * Context: softirq-serialized 315 */ 316static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx, 317 struct oz_usb_hdr *usb_hdr, int len) 318{ 319 struct oz_data *data_hdr = (struct oz_data *)usb_hdr; 320 321 switch (data_hdr->format) { 322 case OZ_DATA_F_MULTIPLE_FIXED: { 323 struct oz_multiple_fixed *body = 324 (struct oz_multiple_fixed *)data_hdr; 325 u8 *data = body->data; 326 int n = (len - sizeof(struct oz_multiple_fixed)+1) 327 / body->unit_size; 328 while (n--) { 329 oz_hcd_data_ind(usb_ctx->hport, body->endpoint, 330 data, body->unit_size); 331 data += body->unit_size; 332 } 333 } 334 break; 335 case OZ_DATA_F_ISOC_FIXED: { 336 struct oz_isoc_fixed *body = 337 (struct oz_isoc_fixed *)data_hdr; 338 int data_len = len-sizeof(struct oz_isoc_fixed)+1; 339 int unit_size = body->unit_size; 340 u8 *data = body->data; 341 int count; 342 int i; 343 if (!unit_size) 344 break; 345 count = data_len/unit_size; 346 for (i = 0; i < count; i++) { 347 oz_hcd_data_ind(usb_ctx->hport, 348 body->endpoint, data, unit_size); 349 data += unit_size; 350 } 351 } 352 break; 353 } 354 355} 356 357/* 358 * This is called when the PD has received a USB element. The type of element 359 * is determined and is then passed to an appropriate handler function. 360 * Context: softirq-serialized 361 */ 362void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt) 363{ 364 struct oz_usb_hdr *usb_hdr = (struct oz_usb_hdr *)(elt + 1); 365 struct oz_usb_ctx *usb_ctx; 366 367 spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]); 368 usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1]; 369 if (usb_ctx) 370 oz_usb_get(usb_ctx); 371 spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]); 372 if (usb_ctx == NULL) 373 return; /* Context has gone so nothing to do. */ 374 if (usb_ctx->stopped) 375 goto done; 376 /* If sequence number is non-zero then check it is not a duplicate. 377 * Zero sequence numbers are always accepted. 378 */ 379 if (usb_hdr->elt_seq_num != 0) { 380 if (((usb_ctx->rx_seq_num - usb_hdr->elt_seq_num) & 0x80) == 0) 381 /* Reject duplicate element. */ 382 goto done; 383 } 384 usb_ctx->rx_seq_num = usb_hdr->elt_seq_num; 385 switch (usb_hdr->type) { 386 case OZ_GET_DESC_RSP: { 387 struct oz_get_desc_rsp *body = 388 (struct oz_get_desc_rsp *)usb_hdr; 389 int data_len = elt->length - 390 sizeof(struct oz_get_desc_rsp) + 1; 391 u16 offs = le16_to_cpu(get_unaligned(&body->offset)); 392 u16 total_size = 393 le16_to_cpu(get_unaligned(&body->total_size)); 394 oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - cnf\n"); 395 oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id, 396 body->rcode, body->data, 397 data_len, offs, total_size); 398 } 399 break; 400 case OZ_SET_CONFIG_RSP: { 401 struct oz_set_config_rsp *body = 402 (struct oz_set_config_rsp *)usb_hdr; 403 oz_hcd_control_cnf(usb_ctx->hport, body->req_id, 404 body->rcode, NULL, 0); 405 } 406 break; 407 case OZ_SET_INTERFACE_RSP: { 408 struct oz_set_interface_rsp *body = 409 (struct oz_set_interface_rsp *)usb_hdr; 410 oz_hcd_control_cnf(usb_ctx->hport, 411 body->req_id, body->rcode, NULL, 0); 412 } 413 break; 414 case OZ_VENDOR_CLASS_RSP: { 415 struct oz_vendor_class_rsp *body = 416 (struct oz_vendor_class_rsp *)usb_hdr; 417 oz_hcd_control_cnf(usb_ctx->hport, body->req_id, 418 body->rcode, body->data, elt->length- 419 sizeof(struct oz_vendor_class_rsp)+1); 420 } 421 break; 422 case OZ_USB_ENDPOINT_DATA: 423 oz_usb_handle_ep_data(usb_ctx, usb_hdr, elt->length); 424 break; 425 } 426done: 427 oz_usb_put(usb_ctx); 428} 429 430/* 431 * Context: softirq, process 432 */ 433void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len) 434{ 435 struct oz_usb_ctx *usb_ctx; 436 437 spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]); 438 usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1]; 439 if (usb_ctx) 440 oz_usb_get(usb_ctx); 441 spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]); 442 if (usb_ctx == NULL) 443 return; /* Context has gone so nothing to do. */ 444 if (!usb_ctx->stopped) { 445 oz_dbg(ON, "Farewell indicated ep = 0x%x\n", ep_num); 446 oz_hcd_data_ind(usb_ctx->hport, ep_num, data, len); 447 } 448 oz_usb_put(usb_ctx); 449}