diff options
Diffstat (limited to 'drivers/staging/westbridge/astoria/gadget/cyasgadget.c')
-rw-r--r-- | drivers/staging/westbridge/astoria/gadget/cyasgadget.c | 2177 |
1 files changed, 0 insertions, 2177 deletions
diff --git a/drivers/staging/westbridge/astoria/gadget/cyasgadget.c b/drivers/staging/westbridge/astoria/gadget/cyasgadget.c deleted file mode 100644 index be851ca54ce..00000000000 --- a/drivers/staging/westbridge/astoria/gadget/cyasgadget.c +++ /dev/null @@ -1,2177 +0,0 @@ -/* cyangadget.c - Linux USB Gadget driver file for the Cypress West Bridge -## =========================== -## Copyright (C) 2010 Cypress Semiconductor -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 51 Franklin Street, Fifth Floor -## Boston, MA 02110-1301, USA. -## =========================== -*/ - -/* - * Cypress West Bridge high/full speed usb device controller code - * Based on the Netchip 2280 device controller by David Brownell - * in the linux 2.6.10 kernel - * - * linux/drivers/usb/gadget/net2280.c - */ - -/* - * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) - * Copyright (C) 2003 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330 - * Boston, MA 02111-1307 USA - */ - -#include "cyasgadget.h" - -#define CY_AS_DRIVER_DESC "cypress west bridge usb gadget" -#define CY_AS_DRIVER_VERSION "REV B" -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -static const char cy_as_driver_name[] = "cy_astoria_gadget"; -static const char cy_as_driver_desc[] = CY_AS_DRIVER_DESC; - -static const char cy_as_ep0name[] = "EP0"; -static const char *cy_as_ep_names[] = { - cy_as_ep0name, "EP1", - "EP2", "EP3", "EP4", "EP5", "EP6", "EP7", "EP8", - "EP9", "EP10", "EP11", "EP12", "EP13", "EP14", "EP15" -}; - -/* forward declarations */ -static void -cyas_ep_reset( - struct cyasgadget_ep *an_ep); - -static int -cyasgadget_fifo_status( - struct usb_ep *_ep); - -static void -cyasgadget_stallcallback( - cy_as_device_handle h, - cy_as_return_status_t status, - uint32_t tag, - cy_as_funct_c_b_type cbtype, - void *cbdata); - -/* variables */ -static cyasgadget *cy_as_gadget_controller; - -static int append_mtp; -module_param(append_mtp, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(append_mtp, - "west bridge to append descriptors for mtp 0=no 1=yes"); - -static int msc_enum_bus_0; -module_param(msc_enum_bus_0, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(msc_enum_bus_0, - "west bridge to enumerate bus 0 as msc 0=no 1=yes"); - -static int msc_enum_bus_1; -module_param(msc_enum_bus_1, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(msc_enum_bus_1, - "west bridge to enumerate bus 1 as msc 0=no 1=yes"); - -/* all Callbacks are placed in this subsection*/ -static void cy_as_gadget_usb_event_callback( - cy_as_device_handle h, - cy_as_usb_event ev, - void *evdata - ) -{ - cyasgadget *cy_as_dev; - #ifndef WESTBRIDGE_NDEBUG - struct usb_ctrlrequest *ctrlreq; - #endif - - /* cy_as_dev = container_of(h, cyasgadget, dev_handle); */ - cy_as_dev = cy_as_gadget_controller; - switch (ev) { - case cy_as_event_usb_suspend: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_suspend received\n"); - #endif - cy_as_dev->driver->suspend(&cy_as_dev->gadget); - break; - - case cy_as_event_usb_resume: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_resume received\n"); - #endif - cy_as_dev->driver->resume(&cy_as_dev->gadget); - break; - - case cy_as_event_usb_reset: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_reset received\n"); - #endif - break; - - case cy_as_event_usb_speed_change: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_speed_change received\n"); - #endif - break; - - case cy_as_event_usb_set_config: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_set_config received\n"); - #endif - break; - - case cy_as_event_usb_setup_packet: - #ifndef WESTBRIDGE_NDEBUG - ctrlreq = (struct usb_ctrlrequest *)evdata; - - cy_as_hal_print_message("<1>_cy_as_event_usb_setup_packet " - "received" - "bRequestType=0x%x," - "bRequest=0x%x," - "wValue=x%x," - "wIndex=0x%x," - "wLength=0x%x,", - ctrlreq->bRequestType, - ctrlreq->bRequest, - ctrlreq->wValue, - ctrlreq->wIndex, - ctrlreq->wLength - ); - #endif - cy_as_dev->outsetupreq = 0; - if ((((uint8_t *)evdata)[0] & USB_DIR_IN) == USB_DIR_OUT) - cy_as_dev->outsetupreq = 1; - cy_as_dev->driver->setup(&cy_as_dev->gadget, - (struct usb_ctrlrequest *)evdata); - break; - - case cy_as_event_usb_status_packet: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_status_packet received\n"); - #endif - break; - - case cy_as_event_usb_inquiry_before: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_inquiry_before received\n"); - #endif - break; - - case cy_as_event_usb_inquiry_after: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_inquiry_after received\n"); - #endif - break; - - case cy_as_event_usb_start_stop: - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<1>_cy_as_event_usb_start_stop received\n"); - #endif - break; - - default: - break; - } -} - -static void cy_as_gadget_mtp_event_callback( - cy_as_device_handle handle, - cy_as_mtp_event evtype, - void *evdata - ) -{ - - cyasgadget *dev = cy_as_gadget_controller; - (void) handle; - - switch (evtype) { - case cy_as_mtp_send_object_complete: - { - cy_as_mtp_send_object_complete_data *send_obj_data = - (cy_as_mtp_send_object_complete_data *) evdata; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<6>MTP EVENT: send_object_complete\n"); - cy_as_hal_print_message( - "<6>_bytes sent = %d\n_send status = %d", - send_obj_data->byte_count, - send_obj_data->status); - #endif - - dev->tmtp_send_complete_data.byte_count = - send_obj_data->byte_count; - dev->tmtp_send_complete_data.status = - send_obj_data->status; - dev->tmtp_send_complete_data.transaction_id = - send_obj_data->transaction_id; - dev->tmtp_send_complete = cy_true; - break; - } - case cy_as_mtp_get_object_complete: - { - cy_as_mtp_get_object_complete_data *get_obj_data = - (cy_as_mtp_get_object_complete_data *) evdata; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<6>MTP EVENT: get_object_complete\n"); - cy_as_hal_print_message( - "<6>_bytes got = %d\n_get status = %d", - get_obj_data->byte_count, get_obj_data->status); - #endif - - dev->tmtp_get_complete_data.byte_count = - get_obj_data->byte_count; - dev->tmtp_get_complete_data.status = - get_obj_data->status; - dev->tmtp_get_complete = cy_true; - break; - } - case cy_as_mtp_block_table_needed: - { - dev->tmtp_need_new_blk_tbl = cy_true; - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<6>MTP EVENT: cy_as_mtp_block_table_needed\n"); - #endif - break; - } - default: - break; - } -} - -static void -cyasgadget_setupreadcallback( - cy_as_device_handle h, - cy_as_end_point_number_t ep, - uint32_t count, - void *buf, - cy_as_return_status_t status) -{ - cyasgadget_ep *an_ep; - cyasgadget_req *an_req; - cyasgadget *cy_as_dev; - unsigned stopped; - unsigned long flags; - (void)buf; - - cy_as_dev = cy_as_gadget_controller; - if (cy_as_dev->driver == NULL) - return; - - an_ep = &cy_as_dev->an_gadget_ep[ep]; - spin_lock_irqsave(&cy_as_dev->lock, flags); - stopped = an_ep->stopped; - -#ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: ep=%d, count=%d, " - "status=%d\n", __func__, ep, count, status); -#endif - - an_req = list_entry(an_ep->queue.next, - cyasgadget_req, queue); - list_del_init(&an_req->queue); - - if (status == CY_AS_ERROR_SUCCESS) - an_req->req.status = 0; - else - an_req->req.status = -status; - an_req->req.actual = count; - an_ep->stopped = 1; - - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - - an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req); - - an_ep->stopped = stopped; - -} -/*called when the write of a setup packet has been completed*/ -static void cyasgadget_setupwritecallback( - cy_as_device_handle h, - cy_as_end_point_number_t ep, - uint32_t count, - void *buf, - cy_as_return_status_t status - ) -{ - cyasgadget_ep *an_ep; - cyasgadget_req *an_req; - cyasgadget *cy_as_dev; - unsigned stopped; - unsigned long flags; - - (void)buf; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called status=0x%x\n", - __func__, status); - #endif - - cy_as_dev = cy_as_gadget_controller; - - if (cy_as_dev->driver == NULL) - return; - - an_ep = &cy_as_dev->an_gadget_ep[ep]; - - spin_lock_irqsave(&cy_as_dev->lock, flags); - - stopped = an_ep->stopped; - -#ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("setup_write_callback: ep=%d, " - "count=%d, status=%d\n", ep, count, status); -#endif - - an_req = list_entry(an_ep->queue.next, cyasgadget_req, queue); - list_del_init(&an_req->queue); - - an_req->req.actual = count; - an_req->req.status = 0; - an_ep->stopped = 1; - - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - - an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req); - - an_ep->stopped = stopped; - -} - -/* called when a read operation has completed.*/ -static void cyasgadget_readcallback( - cy_as_device_handle h, - cy_as_end_point_number_t ep, - uint32_t count, - void *buf, - cy_as_return_status_t status - ) -{ - cyasgadget_ep *an_ep; - cyasgadget_req *an_req; - cyasgadget *cy_as_dev; - unsigned stopped; - cy_as_return_status_t ret; - unsigned long flags; - - (void)h; - (void)buf; - - cy_as_dev = cy_as_gadget_controller; - - if (cy_as_dev->driver == NULL) - return; - - an_ep = &cy_as_dev->an_gadget_ep[ep]; - stopped = an_ep->stopped; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: ep=%d, count=%d, status=%d\n", - __func__, ep, count, status); - #endif - - if (status == CY_AS_ERROR_CANCELED) - return; - - spin_lock_irqsave(&cy_as_dev->lock, flags); - - an_req = list_entry(an_ep->queue.next, cyasgadget_req, queue); - list_del_init(&an_req->queue); - - if (status == CY_AS_ERROR_SUCCESS) - an_req->req.status = 0; - else - an_req->req.status = -status; - - an_req->complete = 1; - an_req->req.actual = count; - an_ep->stopped = 1; - - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req); - - an_ep->stopped = stopped; - - /* We need to call ReadAsync on this end-point - * again, so as to not miss any data packets. */ - if (!an_ep->stopped) { - spin_lock_irqsave(&cy_as_dev->lock, flags); - an_req = 0; - if (!list_empty(&an_ep->queue)) - an_req = list_entry(an_ep->queue.next, - cyasgadget_req, queue); - - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - - if ((an_req) && (an_req->req.status == -EINPROGRESS)) { - ret = cy_as_usb_read_data_async(cy_as_dev->dev_handle, - an_ep->num, cy_false, an_req->req.length, - an_req->req.buf, cyasgadget_readcallback); - - if (ret != CY_AS_ERROR_SUCCESS) - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_read_data_async failed " - "with error code %d\n", ret); - else - an_req->req.status = -EALREADY; - } - } -} - -/* function is called when a usb write operation has completed*/ -static void cyasgadget_writecallback( - cy_as_device_handle h, - cy_as_end_point_number_t ep, - uint32_t count, - void *buf, - cy_as_return_status_t status - ) -{ - cyasgadget_ep *an_ep; - cyasgadget_req *an_req; - cyasgadget *cy_as_dev; - unsigned stopped = 0; - cy_as_return_status_t ret; - unsigned long flags; - - (void)h; - (void)buf; - - cy_as_dev = cy_as_gadget_controller; - if (cy_as_dev->driver == NULL) - return; - - an_ep = &cy_as_dev->an_gadget_ep[ep]; - - if (status == CY_AS_ERROR_CANCELED) - return; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: ep=%d, count=%d, status=%d\n", - __func__, ep, count, status); - #endif - - spin_lock_irqsave(&cy_as_dev->lock, flags); - - an_req = list_entry(an_ep->queue.next, cyasgadget_req, queue); - list_del_init(&an_req->queue); - an_req->req.actual = count; - - /* Verify the status value before setting req.status to zero */ - if (status == CY_AS_ERROR_SUCCESS) - an_req->req.status = 0; - else - an_req->req.status = -status; - - an_ep->stopped = 1; - - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - - an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req); - an_ep->stopped = stopped; - - /* We need to call WriteAsync on this end-point again, so as to not - miss any data packets. */ - if (!an_ep->stopped) { - spin_lock_irqsave(&cy_as_dev->lock, flags); - an_req = 0; - if (!list_empty(&an_ep->queue)) - an_req = list_entry(an_ep->queue.next, - cyasgadget_req, queue); - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - - if ((an_req) && (an_req->req.status == -EINPROGRESS)) { - ret = cy_as_usb_write_data_async(cy_as_dev->dev_handle, - an_ep->num, an_req->req.length, an_req->req.buf, - cy_false, cyasgadget_writecallback); - - if (ret != CY_AS_ERROR_SUCCESS) - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_write_data_async " - "failed with error code %d\n", ret); - else - an_req->req.status = -EALREADY; - } - } -} - -static void cyasgadget_stallcallback( - cy_as_device_handle h, - cy_as_return_status_t status, - uint32_t tag, - cy_as_funct_c_b_type cbtype, - void *cbdata - ) -{ - #ifndef WESTBRIDGE_NDEBUG - if (status != CY_AS_ERROR_SUCCESS) - cy_as_hal_print_message("<1>_set/_clear stall " - "failed with status %d\n", status); - #endif -} - - -/*******************************************************************/ -/* All usb_ep_ops (cyasgadget_ep_ops) are placed in this subsection*/ -/*******************************************************************/ -static int cyasgadget_enable( - struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc - ) -{ - cyasgadget *an_dev; - cyasgadget_ep *an_ep; - u32 max, tmp; - unsigned long flags; - - an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst); - if (!_ep || !desc || an_ep->desc || _ep->name == cy_as_ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - an_dev = an_ep->dev; - if (!an_dev->driver || an_dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff; - - spin_lock_irqsave(&an_dev->lock, flags); - _ep->maxpacket = max & 0x7ff; - an_ep->desc = desc; - - /* ep_reset() has already been called */ - an_ep->stopped = 0; - an_ep->out_overflow = 0; - - if (an_ep->cyepconfig.enabled != cy_true) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_end_point_config EP %s mismatch " - "on enabled\n", an_ep->usb_ep_inst.name); - #endif - spin_unlock_irqrestore(&an_dev->lock, flags); - return -EINVAL; - } - - tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); - an_ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0; - - spin_unlock_irqrestore(&an_dev->lock, flags); - - switch (tmp) { - case USB_ENDPOINT_XFER_ISOC: - if (an_ep->cyepconfig.type != cy_as_usb_iso) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_end_point_config EP %s mismatch " - "on type %d %d\n", an_ep->usb_ep_inst.name, - an_ep->cyepconfig.type, cy_as_usb_iso); - #endif - return -EINVAL; - } - break; - case USB_ENDPOINT_XFER_INT: - if (an_ep->cyepconfig.type != cy_as_usb_int) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_end_point_config EP %s mismatch " - "on type %d %d\n", an_ep->usb_ep_inst.name, - an_ep->cyepconfig.type, cy_as_usb_int); - #endif - return -EINVAL; - } - break; - default: - if (an_ep->cyepconfig.type != cy_as_usb_bulk) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_end_point_config EP %s mismatch " - "on type %d %d\n", an_ep->usb_ep_inst.name, - an_ep->cyepconfig.type, cy_as_usb_bulk); - #endif - return -EINVAL; - } - break; - } - - tmp = desc->bEndpointAddress; - an_ep->is_in = (tmp & USB_DIR_IN) != 0; - - if ((an_ep->cyepconfig.dir == cy_as_usb_in) && - (!an_ep->is_in)) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_end_point_config EP %s mismatch " - "on dir %d %d\n", an_ep->usb_ep_inst.name, - an_ep->cyepconfig.dir, cy_as_usb_in); - #endif - return -EINVAL; - } else if ((an_ep->cyepconfig.dir == cy_as_usb_out) && - (an_ep->is_in)) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_end_point_config EP %s mismatch " - "on dir %d %d\n", an_ep->usb_ep_inst.name, - an_ep->cyepconfig.dir, cy_as_usb_out); - #endif - return -EINVAL; - } - - cy_as_usb_clear_stall(an_dev->dev_handle, an_ep->num, - cyasgadget_stallcallback, 0); - - cy_as_hal_print_message("%s enabled %s (ep%d-%d) max %04x\n", - __func__, _ep->name, an_ep->num, tmp, max); - - return 0; -} - -static int cyasgadget_disable( - struct usb_ep *_ep - ) -{ - cyasgadget_ep *an_ep; - unsigned long flags; - - an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst); - if (!_ep || !an_ep->desc || _ep->name == cy_as_ep0name) - return -EINVAL; - - spin_lock_irqsave(&an_ep->dev->lock, flags); - cyas_ep_reset(an_ep); - - spin_unlock_irqrestore(&an_ep->dev->lock, flags); - return 0; -} - -static struct usb_request *cyasgadget_alloc_request( - struct usb_ep *_ep, gfp_t gfp_flags - ) -{ - cyasgadget_ep *an_ep; - cyasgadget_req *an_req; - - if (!_ep) - return NULL; - - an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst); - - an_req = kzalloc(sizeof(cyasgadget_req), gfp_flags); - if (!an_req) - return NULL; - - an_req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&an_req->queue); - - return &an_req->req; -} - -static void cyasgadget_free_request( - struct usb_ep *_ep, - struct usb_request *_req - ) -{ - cyasgadget_req *an_req; - - if (!_ep || !_req) - return; - - an_req = container_of(_req, cyasgadget_req, req); - - kfree(an_req); -} - -/* Load a packet into the fifo we use for usb IN transfers. - * works for all endpoints. */ -static int cyasgadget_queue( - struct usb_ep *_ep, - struct usb_request *_req, - gfp_t gfp_flags - ) -{ - cyasgadget_req *as_req; - cyasgadget_ep *as_ep; - cyasgadget *cy_as_dev; - unsigned long flags; - cy_as_return_status_t ret = 0; - - as_req = container_of(_req, cyasgadget_req, req); - if (!_req || !_req->complete || !_req->buf - || !list_empty(&as_req->queue)) - return -EINVAL; - - as_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst); - - if (!_ep || (!as_ep->desc && (as_ep->num != 0))) - return -EINVAL; - - cy_as_dev = as_ep->dev; - if (!cy_as_dev->driver || - cy_as_dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&cy_as_dev->lock, flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - - /* Call Async functions */ - if (as_ep->is_in) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_write_data_async being called " - "on ep %d\n", as_ep->num); - #endif - - ret = cy_as_usb_write_data_async(cy_as_dev->dev_handle, - as_ep->num, _req->length, _req->buf, - cy_false, cyasgadget_writecallback); - if (ret != CY_AS_ERROR_SUCCESS) - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_write_data_async failed with " - "error code %d\n", ret); - else - _req->status = -EALREADY; - } else if (as_ep->num == 0) { - /* - ret = cy_as_usb_write_data_async(cy_as_dev->dev_handle, - as_ep->num, _req->length, _req->buf, cy_false, - cyasgadget_setupwritecallback); - - if (ret != CY_AS_ERROR_SUCCESS) - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_write_data_async failed with error " - "code %d\n", ret); - */ - if ((cy_as_dev->outsetupreq) && (_req->length)) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_read_data_async " - "being called on ep %d\n", - as_ep->num); - #endif - - ret = cy_as_usb_read_data_async ( - cy_as_dev->dev_handle, as_ep->num, - cy_true, _req->length, _req->buf, - cyasgadget_setupreadcallback); - - if (ret != CY_AS_ERROR_SUCCESS) - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_read_data_async failed with " - "error code %d\n", ret); - - } else { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_write_data_async " - "being called on ep %d\n", - as_ep->num); - #endif - - ret = cy_as_usb_write_data_async(cy_as_dev->dev_handle, - as_ep->num, _req->length, _req->buf, cy_false, - cyasgadget_setupwritecallback); - - if (ret != CY_AS_ERROR_SUCCESS) - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_write_data_async failed with " - "error code %d\n", ret); - } - - } else if (list_empty(&as_ep->queue)) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_read_data_async being called since " - "ep queue empty%d\n", ret); - #endif - - ret = cy_as_usb_read_data_async(cy_as_dev->dev_handle, - as_ep->num, cy_false, _req->length, _req->buf, - cyasgadget_readcallback); - if (ret != CY_AS_ERROR_SUCCESS) - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_read_data_async failed with error " - "code %d\n", ret); - else - _req->status = -EALREADY; - } - - spin_lock_irqsave(&cy_as_dev->lock, flags); - - if (as_req) - list_add_tail(&as_req->queue, &as_ep->queue); - - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - - return 0; -} - -/* dequeue request */ -static int cyasgadget_dequeue( - struct usb_ep *_ep, - struct usb_request *_req - ) -{ - cyasgadget_ep *an_ep; - cyasgadget *dev; - an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst); - dev = an_ep->dev; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - cy_as_usb_cancel_async(dev->dev_handle, an_ep->num); - - return 0; -} - -static int cyasgadget_set_halt( - struct usb_ep *_ep, - int value - ) -{ - cyasgadget_ep *an_ep; - int retval = 0; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - an_ep = container_of(_ep, cyasgadget_ep, usb_ep_inst); - if (!_ep || (!an_ep->desc && an_ep->num != 0)) - return -EINVAL; - - if (!an_ep->dev->driver || an_ep->dev->gadget.speed == - USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - if (an_ep->desc /* not ep0 */ && - (an_ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC) - return -EINVAL; - - if (!list_empty(&an_ep->queue)) - retval = -EAGAIN; - else if (an_ep->is_in && value && - cyasgadget_fifo_status(_ep) != 0) - retval = -EAGAIN; - else { - if (value) { - cy_as_usb_set_stall(an_ep->dev->dev_handle, - an_ep->num, cyasgadget_stallcallback, 0); - } else { - cy_as_usb_clear_stall(an_ep->dev->dev_handle, - an_ep->num, cyasgadget_stallcallback, 0); - } - } - - return retval; -} - -static int cyasgadget_fifo_status( - struct usb_ep *_ep - ) -{ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - return 0; -} - -static void cyasgadget_fifo_flush( - struct usb_ep *_ep - ) -{ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif -} - -static struct usb_ep_ops cyasgadget_ep_ops = { - .enable = cyasgadget_enable, - .disable = cyasgadget_disable, - .alloc_request = cyasgadget_alloc_request, - .free_request = cyasgadget_free_request, - .queue = cyasgadget_queue, - .dequeue = cyasgadget_dequeue, - .set_halt = cyasgadget_set_halt, - .fifo_status = cyasgadget_fifo_status, - .fifo_flush = cyasgadget_fifo_flush, -}; - -/*************************************************************/ -/*This subsection contains all usb_gadget_ops cyasgadget_ops */ -/*************************************************************/ -static int cyasgadget_get_frame( - struct usb_gadget *_gadget - ) -{ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - return 0; -} - -static int cyasgadget_wakeup( - struct usb_gadget *_gadget - ) -{ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - return 0; -} - -static int cyasgadget_set_selfpowered( - struct usb_gadget *_gadget, - int value - ) -{ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - return 0; -} - -static int cyasgadget_pullup( - struct usb_gadget *_gadget, - int is_on - ) -{ - struct cyasgadget *cy_as_dev; - unsigned long flags; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - if (!_gadget) - return -ENODEV; - - cy_as_dev = container_of(_gadget, cyasgadget, gadget); - - spin_lock_irqsave(&cy_as_dev->lock, flags); - cy_as_dev->softconnect = (is_on != 0); - if (is_on) - cy_as_usb_connect(cy_as_dev->dev_handle, 0, 0); - else - cy_as_usb_disconnect(cy_as_dev->dev_handle, 0, 0); - - spin_unlock_irqrestore(&cy_as_dev->lock, flags); - - return 0; -} - -static int cyasgadget_ioctl( - struct usb_gadget *_gadget, - unsigned code, - unsigned long param - ) -{ - int err = 0; - int retval = 0; - int ret_stat = 0; - cyasgadget *dev = cy_as_gadget_controller; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called, code=%d, param=%ld\n", - __func__, code, param); - #endif - /* - * extract the type and number bitfields, and don't decode - * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() - */ - if (_IOC_TYPE(code) != CYASGADGET_IOC_MAGIC) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s, bad magic number = 0x%x\n", - __func__, _IOC_TYPE(code)); - #endif - return -ENOTTY; - } - - if (_IOC_NR(code) > CYASGADGET_IOC_MAXNR) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s, bad ioctl code = 0x%x\n", - __func__, _IOC_NR(code)); - #endif - return -ENOTTY; - } - - /* - * the direction is a bitmask, and VERIFY_WRITE catches R/W - * transfers. `Type' is user-oriented, while - * access_ok is kernel-oriented, so the concept of "read" and - * "write" is reversed - */ - if (_IOC_DIR(code) & _IOC_READ) - err = !access_ok(VERIFY_WRITE, - (void __user *)param, _IOC_SIZE(code)); - else if (_IOC_DIR(code) & _IOC_WRITE) - err = !access_ok(VERIFY_READ, - (void __user *)param, _IOC_SIZE(code)); - - if (err) { - cy_as_hal_print_message("%s, bad ioctl dir = 0x%x\n", - __func__, _IOC_DIR(code)); - return -EFAULT; - } - - switch (code) { - case CYASGADGET_GETMTPSTATUS: - { - cy_as_gadget_ioctl_tmtp_status *usr_d = - (cy_as_gadget_ioctl_tmtp_status *)param; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: got CYASGADGET_GETMTPSTATUS\n", - __func__); - #endif - - retval = __put_user(dev->tmtp_send_complete, - (uint32_t __user *)(&(usr_d->tmtp_send_complete))); - retval = __put_user(dev->tmtp_get_complete, - (uint32_t __user *)(&(usr_d->tmtp_get_complete))); - retval = __put_user(dev->tmtp_need_new_blk_tbl, - (uint32_t __user *)(&(usr_d->tmtp_need_new_blk_tbl))); - - if (copy_to_user((&(usr_d->tmtp_send_complete_data)), - (&(dev->tmtp_send_complete_data)), - sizeof(cy_as_gadget_ioctl_send_object))) - return -EFAULT; - - if (copy_to_user((&(usr_d->tmtp_get_complete_data)), - (&(dev->tmtp_get_complete_data)), - sizeof(cy_as_gadget_ioctl_get_object))) - return -EFAULT; - break; - } - case CYASGADGET_CLEARTMTPSTATUS: - { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s got CYASGADGET_CLEARTMTPSTATUS\n", - __func__); - #endif - - dev->tmtp_send_complete = 0; - dev->tmtp_get_complete = 0; - dev->tmtp_need_new_blk_tbl = 0; - - break; - } - case CYASGADGET_INITSOJ: - { - cy_as_gadget_ioctl_i_s_o_j_d k_d; - cy_as_gadget_ioctl_i_s_o_j_d *usr_d = - (cy_as_gadget_ioctl_i_s_o_j_d *)param; - cy_as_mtp_block_table blk_table; - struct scatterlist sg; - char *alloc_filename; - struct file *file_to_allocate; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s got CYASGADGET_INITSOJ\n", - __func__); - #endif - - memset(&blk_table, 0, sizeof(blk_table)); - - /* Get user argument structure */ - if (copy_from_user(&k_d, usr_d, - sizeof(cy_as_gadget_ioctl_i_s_o_j_d))) - return -EFAULT; - - /* better use fixed size buff*/ - alloc_filename = kmalloc(k_d.name_length + 1, GFP_KERNEL); - if (alloc_filename == NULL) - return -ENOMEM; - - /* get the filename */ - if (copy_from_user(alloc_filename, k_d.file_name, - k_d.name_length + 1)) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: CYASGADGET_INITSOJ, " - "copy file name from user space failed\n", - __func__); - #endif - kfree(alloc_filename); - return -EFAULT; - } - - file_to_allocate = filp_open(alloc_filename, O_RDWR, 0); - - if (!IS_ERR(file_to_allocate)) { - - struct address_space *mapping = - file_to_allocate->f_mapping; - const struct address_space_operations *a_ops = - mapping->a_ops; - struct inode *inode = mapping->host; - struct inode *alloc_inode = - file_to_allocate->f_path.dentry->d_inode; - uint32_t num_clusters = 0; - struct buffer_head bh; - struct kstat stat; - int nr_pages = 0; - int ret_stat = 0; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: fhandle is OK, " - "calling vfs_getattr\n", __func__); - #endif - - ret_stat = vfs_getattr(file_to_allocate->f_path.mnt, - file_to_allocate->f_path.dentry, &stat); - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: returned from " - "vfs_getattr() stat->blksize=0x%lx\n", - __func__, stat.blksize); - #endif - - /* TODO: get this from disk properties - * (from blockdevice)*/ - #define SECTOR_SIZE 512 - if (stat.blksize != 0) { - num_clusters = (k_d.num_bytes) / SECTOR_SIZE; - - if (((k_d.num_bytes) % SECTOR_SIZE) != 0) - num_clusters++; - } else { - goto initsoj_safe_exit; - } - - bh.b_state = 0; - bh.b_blocknr = 0; - /* block size is arbitrary , we'll use sector size*/ - bh.b_size = SECTOR_SIZE; - - - - /* clear dirty pages in page cache - * (if were any allocated) */ - nr_pages = (k_d.num_bytes) / (PAGE_CACHE_SIZE); - - if (((k_d.num_bytes) % (PAGE_CACHE_SIZE)) != 0) - nr_pages++; - - #ifndef WESTBRIDGE_NDEBUG - /*check out how many pages where actually allocated */ - if (mapping->nrpages != nr_pages) - cy_as_hal_print_message("%s mpage_cleardirty " - "mapping->nrpages %d != num_pages %d\n", - __func__, (int) mapping->nrpages, - nr_pages); - - cy_as_hal_print_message("%s: calling " - "mpage_cleardirty() " - "for %d pages\n", __func__, nr_pages); - #endif - - ret_stat = mpage_cleardirty(mapping, nr_pages); - - /*fill up the the block table from the addr mapping */ - if (a_ops->bmap) { - int8_t blk_table_idx = -1; - uint32_t file_block_idx = 0; - uint32_t last_blk_addr_map = 0, - curr_blk_addr_map = 0; - - #ifndef WESTBRIDGE_NDEBUG - if (alloc_inode->i_bytes == 0) - cy_as_hal_print_message( - "%s: alloc_inode->ibytes =0\n", - __func__); - #endif - - /* iterate through the list of - * blocks (not clusters)*/ - for (file_block_idx = 0; - file_block_idx < num_clusters - /*inode->i_bytes*/; file_block_idx++) { - - /* returns starting sector number */ - curr_blk_addr_map = - a_ops->bmap(mapping, - file_block_idx); - - /*no valid mapping*/ - if (curr_blk_addr_map == 0) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s:hit invalid " - "mapping\n", __func__); - #endif - break; - } else if (curr_blk_addr_map != - (last_blk_addr_map + 1) || - (blk_table.num_blocks - [blk_table_idx] == 65535)) { - - /* next table entry */ - blk_table_idx++; - /* starting sector of a - * scattered cluster*/ - blk_table.start_blocks - [blk_table_idx] = - curr_blk_addr_map; - /* ++ num of blocks in cur - * table entry*/ - blk_table. - num_blocks[blk_table_idx]++; - - #ifndef WESTBRIDGE_NDEBUG - if (file_block_idx != 0) - cy_as_hal_print_message( - "<*> next table " - "entry:%d required\n", - blk_table_idx); - #endif - } else { - /*add contiguous block*/ - blk_table.num_blocks - [blk_table_idx]++; - } /*if (curr_blk_addr_map == 0)*/ - - last_blk_addr_map = curr_blk_addr_map; - } /* end for (file_block_idx = 0; file_block_idx - < inode->i_bytes;) */ - - #ifndef WESTBRIDGE_NDEBUG - /*print result for verification*/ - { - int i; - cy_as_hal_print_message( - "%s: print block table " - "mapping:\n", - __func__); - for (i = 0; i <= blk_table_idx; i++) { - cy_as_hal_print_message( - "<1> %d 0x%x 0x%x\n", i, - blk_table.start_blocks[i], - blk_table.num_blocks[i]); - } - } - #endif - - /* copy the block table to user - * space (for debug purposes) */ - retval = __put_user( - blk_table.start_blocks[blk_table_idx], - (uint32_t __user *) - (&(usr_d->blk_addr_p))); - - retval = __put_user( - blk_table.num_blocks[blk_table_idx], - (uint32_t __user *) - (&(usr_d->blk_count_p))); - - blk_table_idx++; - retval = __put_user(blk_table_idx, - (uint32_t __user *) - (&(usr_d->item_count))); - - } /*end if (a_ops->bmap)*/ - - filp_close(file_to_allocate, NULL); - - dev->tmtp_send_complete = 0; - dev->tmtp_need_new_blk_tbl = 0; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: calling cy_as_mtp_init_send_object()\n", - __func__); - #endif - sg_init_one(&sg, &blk_table, sizeof(blk_table)); - ret_stat = cy_as_mtp_init_send_object(dev->dev_handle, - (cy_as_mtp_block_table *)&sg, - k_d.num_bytes, 0, 0); - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: returned from " - "cy_as_mtp_init_send_object()\n", __func__); - #endif - - } - #ifndef WESTBRIDGE_NDEBUG - else { - cy_as_hal_print_message( - "%s: failed to allocate the file %s\n", - __func__, alloc_filename); - } /* end if (file_to_allocate)*/ - #endif - kfree(alloc_filename); -initsoj_safe_exit: - ret_stat = 0; - retval = __put_user(ret_stat, - (uint32_t __user *)(&(usr_d->ret_val))); - - break; - } - case CYASGADGET_INITGOJ: - { - cy_as_gadget_ioctl_i_g_o_j_d k_d; - cy_as_gadget_ioctl_i_g_o_j_d *usr_d = - (cy_as_gadget_ioctl_i_g_o_j_d *)param; - cy_as_mtp_block_table blk_table; - struct scatterlist sg; - char *map_filename; - struct file *file_to_map; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: got CYASGADGET_INITGOJ\n", - __func__); - #endif - - memset(&blk_table, 0, sizeof(blk_table)); - - /* Get user argument sturcutre */ - if (copy_from_user(&k_d, usr_d, - sizeof(cy_as_gadget_ioctl_i_g_o_j_d))) - return -EFAULT; - - map_filename = kmalloc(k_d.name_length + 1, GFP_KERNEL); - if (map_filename == NULL) - return -ENOMEM; - if (copy_from_user(map_filename, k_d.file_name, - k_d.name_length + 1)) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: copy file name from " - "user space failed\n", __func__); - #endif - kfree(map_filename); - return -EFAULT; - } - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<*>%s: opening %s for kernel " - "mode access map\n", __func__, map_filename); - #endif - file_to_map = filp_open(map_filename, O_RDWR, 0); - if (file_to_map) { - struct address_space *mapping = file_to_map->f_mapping; - const struct address_space_operations - *a_ops = mapping->a_ops; - struct inode *inode = mapping->host; - - int8_t blk_table_idx = -1; - uint32_t file_block_idx = 0; - uint32_t last_blk_addr_map = 0, curr_blk_addr_map = 0; - - /*verify operation exists*/ - if (a_ops->bmap) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<*>%s: bmap found, i_bytes=0x%x, " - "i_size=0x%x, i_blocks=0x%x\n", - __func__, inode->i_bytes, - (unsigned int) inode->i_size, - (unsigned int) inode->i_blocks); - #endif - - k_d.num_bytes = inode->i_size; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "<*>%s: k_d.num_bytes=0x%x\n", - __func__, k_d.num_bytes); - #endif - - for (file_block_idx = 0; - file_block_idx < inode->i_size; - file_block_idx++) { - curr_blk_addr_map = - a_ops->bmap(mapping, - file_block_idx); - - if (curr_blk_addr_map == 0) { - /*no valid mapping*/ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: no valid " - "mapping\n", __func__); - #endif - break; - } else if (curr_blk_addr_map != - (last_blk_addr_map + 1)) { - /*non-contiguous break*/ - blk_table_idx++; - blk_table.start_blocks - [blk_table_idx] = - curr_blk_addr_map; - blk_table.num_blocks - [blk_table_idx]++; - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: found non-" - "contiguous break", - __func__); - #endif - } else { - /*add contiguous block*/ - blk_table.num_blocks - [blk_table_idx]++; - } - last_blk_addr_map = curr_blk_addr_map; - } - - /*print result for verification*/ - #ifndef WESTBRIDGE_NDEBUG - { - int i = 0; - - for (i = 0; i <= blk_table_idx; i++) { - cy_as_hal_print_message( - "%s %d 0x%x 0x%x\n", - __func__, i, - blk_table.start_blocks[i], - blk_table.num_blocks[i]); - } - } - #endif - } else { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: could not find " - "a_ops->bmap\n", __func__); - #endif - return -EFAULT; - } - - filp_close(file_to_map, NULL); - - dev->tmtp_get_complete = 0; - dev->tmtp_need_new_blk_tbl = 0; - - ret_stat = __put_user( - blk_table.start_blocks[blk_table_idx], - (uint32_t __user *)(&(usr_d->blk_addr_p))); - - ret_stat = __put_user( - blk_table.num_blocks[blk_table_idx], - (uint32_t __user *)(&(usr_d->blk_count_p))); - - sg_init_one(&sg, &blk_table, sizeof(blk_table)); - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: calling cy_as_mtp_init_get_object() " - "start=0x%x, num =0x%x, tid=0x%x, " - "num_bytes=0x%x\n", - __func__, - blk_table.start_blocks[0], - blk_table.num_blocks[0], - k_d.tid, - k_d.num_bytes); - #endif - - ret_stat = cy_as_mtp_init_get_object( - dev->dev_handle, - (cy_as_mtp_block_table *)&sg, - k_d.num_bytes, k_d.tid, 0, 0); - if (ret_stat != CY_AS_ERROR_SUCCESS) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: cy_as_mtp_init_get_object " - "failed ret_stat=0x%x\n", - __func__, ret_stat); - #endif - } - } - #ifndef WESTBRIDGE_NDEBUG - else { - cy_as_hal_print_message( - "%s: failed to open file %s\n", - __func__, map_filename); - } - #endif - kfree(map_filename); - - ret_stat = 0; - retval = __put_user(ret_stat, (uint32_t __user *) - (&(usr_d->ret_val))); - break; - } - case CYASGADGET_CANCELSOJ: - { - cy_as_gadget_ioctl_cancel *usr_d = - (cy_as_gadget_ioctl_cancel *)param; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message( - "%s: got CYASGADGET_CANCELSOJ\n", - __func__); - #endif - - ret_stat = cy_as_mtp_cancel_send_object(dev->dev_handle, 0, 0); - - retval = __put_user(ret_stat, (uint32_t __user *) - (&(usr_d->ret_val))); - break; - } - case CYASGADGET_CANCELGOJ: - { - cy_as_gadget_ioctl_cancel *usr_d = - (cy_as_gadget_ioctl_cancel *)param; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: got CYASGADGET_CANCELGOJ\n", - __func__); - #endif - - ret_stat = cy_as_mtp_cancel_get_object(dev->dev_handle, 0, 0); - - retval = __put_user(ret_stat, - (uint32_t __user *)(&(usr_d->ret_val))); - break; - } - default: - { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: unknown ioctl received: %d\n", - __func__, code); - - cy_as_hal_print_message("%s: known codes:\n" - "CYASGADGET_GETMTPSTATUS=%d\n" - "CYASGADGET_CLEARTMTPSTATUS=%d\n" - "CYASGADGET_INITSOJ=%d\n" - "CYASGADGET_INITGOJ=%d\n" - "CYASGADGET_CANCELSOJ=%d\n" - "CYASGADGET_CANCELGOJ=%d\n", - __func__, - CYASGADGET_GETMTPSTATUS, - CYASGADGET_CLEARTMTPSTATUS, - CYASGADGET_INITSOJ, - CYASGADGET_INITGOJ, - CYASGADGET_CANCELSOJ, - CYASGADGET_CANCELGOJ); - #endif - break; - } - } - - return 0; -} - -static const struct usb_gadget_ops cyasgadget_ops = { - .get_frame = cyasgadget_get_frame, - .wakeup = cyasgadget_wakeup, - .set_selfpowered = cyasgadget_set_selfpowered, - .pullup = cyasgadget_pullup, - .ioctl = cyasgadget_ioctl, -}; - - -/* keeping it simple: - * - one bus driver, initted first; - * - one function driver, initted second - * - * most of the work to support multiple controllers would - * be to associate this gadget driver with all of them, or - * perhaps to bind specific drivers to specific devices. - */ - -static void cyas_ep_reset( - cyasgadget_ep *an_ep - ) -{ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - an_ep->desc = NULL; - INIT_LIST_HEAD(&an_ep->queue); - - an_ep->stopped = 0; - an_ep->is_in = 0; - an_ep->is_iso = 0; - an_ep->usb_ep_inst.maxpacket = ~0; - an_ep->usb_ep_inst.ops = &cyasgadget_ep_ops; -} - -static void cyas_usb_reset( - cyasgadget *cy_as_dev - ) -{ - cy_as_return_status_t ret; - cy_as_usb_enum_control config; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_device *dev_p = (cy_as_device *)cy_as_dev->dev_handle; - - cy_as_hal_print_message("<1>%s called mtp_firmware=0x%x\n", - __func__, dev_p->is_mtp_firmware); - #endif - - ret = cy_as_misc_release_resource(cy_as_dev->dev_handle, - cy_as_bus_u_s_b); - if (ret != CY_AS_ERROR_SUCCESS && ret != - CY_AS_ERROR_RESOURCE_NOT_OWNED) { - cy_as_hal_print_message("<1>_cy_as_gadget: cannot " - "release usb resource: failed with error code %d\n", - ret); - return; - } - - cy_as_dev->gadget.speed = USB_SPEED_HIGH; - - ret = cy_as_usb_start(cy_as_dev->dev_handle, 0, 0); - if (ret != CY_AS_ERROR_SUCCESS) { - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_start failed with error code %d\n", - ret); - return; - } - /* P port will do enumeration, not West Bridge */ - config.antioch_enumeration = cy_false; - /* 1 2 : 1-BUS_NUM , 2:Storage_device number, SD - is bus 1*/ - - /* TODO: add module param to enumerate mass storage */ - config.mass_storage_interface = 0; - - if (append_mtp) { - ret = cy_as_mtp_start(cy_as_dev->dev_handle, - cy_as_gadget_mtp_event_callback, 0, 0); - if (ret == CY_AS_ERROR_SUCCESS) { - cy_as_hal_print_message("MTP start passed, enumerating " - "MTP interface\n"); - config.mtp_interface = append_mtp; - /*Do not enumerate NAND storage*/ - config.devices_to_enumerate[0][0] = cy_false; - - /*enumerate SD storage as MTP*/ - config.devices_to_enumerate[1][0] = cy_true; - } - } else { - cy_as_hal_print_message("MTP start not attempted, not " - "enumerating MTP interface\n"); - config.mtp_interface = 0; - /* enumerate mass storage based on module parameters */ - config.devices_to_enumerate[0][0] = msc_enum_bus_0; - config.devices_to_enumerate[1][0] = msc_enum_bus_1; - } - - ret = cy_as_usb_set_enum_config(cy_as_dev->dev_handle, - &config, 0, 0); - if (ret != CY_AS_ERROR_SUCCESS) { - cy_as_hal_print_message("<1>_cy_as_gadget: " - "cy_as_usb_set_enum_config failed with error " - "code %d\n", ret); - return; - } - - cy_as_usb_set_physical_configuration(cy_as_dev->dev_handle, 1); - -} - -static void cyas_usb_reinit( - cyasgadget *cy_as_dev - ) -{ - int index = 0; - cyasgadget_ep *an_ep_p; - cy_as_return_status_t ret; - cy_as_device *dev_p = (cy_as_device *)cy_as_dev->dev_handle; - - INIT_LIST_HEAD(&cy_as_dev->gadget.ep_list); - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called, is_mtp_firmware = " - "0x%x\n", __func__, dev_p->is_mtp_firmware); - #endif - - /* Init the end points */ - for (index = 1; index <= 15; index++) { - an_ep_p = &cy_as_dev->an_gadget_ep[index]; - cyas_ep_reset(an_ep_p); - an_ep_p->usb_ep_inst.name = cy_as_ep_names[index]; - an_ep_p->dev = cy_as_dev; - an_ep_p->num = index; - memset(&an_ep_p->cyepconfig, 0, sizeof(an_ep_p->cyepconfig)); - - /* EP0, EPs 2,4,6,8 need not be added */ - if ((index <= 8) && (index % 2 == 0) && - (!dev_p->is_mtp_firmware)) { - /* EP0 is 64 and EPs 2,4,6,8 not allowed */ - cy_as_dev->an_gadget_ep[index].fifo_size = 0; - } else { - if (index == 1) - an_ep_p->fifo_size = 64; - else - an_ep_p->fifo_size = 512; - list_add_tail(&an_ep_p->usb_ep_inst.ep_list, - &cy_as_dev->gadget.ep_list); - } - } - /* need to setendpointconfig before usb connect, this is not - * quite compatible with gadget methodology (ep_enable called - * by gadget after connect), therefore need to set config in - * initialization and verify compatibility in ep_enable, - * kick up error otherwise*/ - an_ep_p = &cy_as_dev->an_gadget_ep[3]; - an_ep_p->cyepconfig.enabled = cy_true; - an_ep_p->cyepconfig.dir = cy_as_usb_out; - an_ep_p->cyepconfig.type = cy_as_usb_bulk; - an_ep_p->cyepconfig.size = 0; - an_ep_p->cyepconfig.physical = 1; - ret = cy_as_usb_set_end_point_config(an_ep_p->dev->dev_handle, - 3, &an_ep_p->cyepconfig); - if (ret != CY_AS_ERROR_SUCCESS) { - cy_as_hal_print_message("cy_as_usb_set_end_point_config " - "failed with error code %d\n", ret); - } - - cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 3, 0, 0); - - an_ep_p = &cy_as_dev->an_gadget_ep[5]; - an_ep_p->cyepconfig.enabled = cy_true; - an_ep_p->cyepconfig.dir = cy_as_usb_in; - an_ep_p->cyepconfig.type = cy_as_usb_bulk; - an_ep_p->cyepconfig.size = 0; - an_ep_p->cyepconfig.physical = 2; - ret = cy_as_usb_set_end_point_config(an_ep_p->dev->dev_handle, - 5, &an_ep_p->cyepconfig); - if (ret != CY_AS_ERROR_SUCCESS) { - cy_as_hal_print_message("cy_as_usb_set_end_point_config " - "failed with error code %d\n", ret); - } - - cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 5, 0, 0); - - an_ep_p = &cy_as_dev->an_gadget_ep[9]; - an_ep_p->cyepconfig.enabled = cy_true; - an_ep_p->cyepconfig.dir = cy_as_usb_in; - an_ep_p->cyepconfig.type = cy_as_usb_bulk; - an_ep_p->cyepconfig.size = 0; - an_ep_p->cyepconfig.physical = 4; - ret = cy_as_usb_set_end_point_config(an_ep_p->dev->dev_handle, - 9, &an_ep_p->cyepconfig); - if (ret != CY_AS_ERROR_SUCCESS) { - cy_as_hal_print_message("cy_as_usb_set_end_point_config " - "failed with error code %d\n", ret); - } - - cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 9, 0, 0); - - if (dev_p->mtp_count != 0) { - /* these need to be set for compatibility with - * the gadget_enable logic */ - an_ep_p = &cy_as_dev->an_gadget_ep[2]; - an_ep_p->cyepconfig.enabled = cy_true; - an_ep_p->cyepconfig.dir = cy_as_usb_out; - an_ep_p->cyepconfig.type = cy_as_usb_bulk; - an_ep_p->cyepconfig.size = 0; - an_ep_p->cyepconfig.physical = 0; - cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 2, 0, 0); - - an_ep_p = &cy_as_dev->an_gadget_ep[6]; - an_ep_p->cyepconfig.enabled = cy_true; - an_ep_p->cyepconfig.dir = cy_as_usb_in; - an_ep_p->cyepconfig.type = cy_as_usb_bulk; - an_ep_p->cyepconfig.size = 0; - an_ep_p->cyepconfig.physical = 0; - cy_as_usb_set_stall(an_ep_p->dev->dev_handle, 6, 0, 0); - } - - cyas_ep_reset(&cy_as_dev->an_gadget_ep[0]); - cy_as_dev->an_gadget_ep[0].usb_ep_inst.name = cy_as_ep_names[0]; - cy_as_dev->an_gadget_ep[0].dev = cy_as_dev; - cy_as_dev->an_gadget_ep[0].num = 0; - cy_as_dev->an_gadget_ep[0].fifo_size = 64; - - cy_as_dev->an_gadget_ep[0].usb_ep_inst.maxpacket = 64; - cy_as_dev->gadget.ep0 = &cy_as_dev->an_gadget_ep[0].usb_ep_inst; - cy_as_dev->an_gadget_ep[0].stopped = 0; - INIT_LIST_HEAD(&cy_as_dev->gadget.ep0->ep_list); -} - -static void cyas_ep0_start( - cyasgadget *dev - ) -{ - cy_as_return_status_t ret; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - ret = cy_as_usb_register_callback(dev->dev_handle, - cy_as_gadget_usb_event_callback); - if (ret != CY_AS_ERROR_SUCCESS) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: cy_as_usb_register_callback " - "failed with error code %d\n", __func__, ret); - #endif - return; - } - - ret = cy_as_usb_commit_config(dev->dev_handle, 0, 0); - if (ret != CY_AS_ERROR_SUCCESS) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: cy_as_usb_commit_config " - "failed with error code %d\n", __func__, ret); - #endif - return; - } - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: cy_as_usb_commit_config " - "message sent\n", __func__); - #endif - - ret = cy_as_usb_connect(dev->dev_handle, 0, 0); - if (ret != CY_AS_ERROR_SUCCESS) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: cy_as_usb_connect failed " - "with error code %d\n", __func__, ret); - #endif - return; - } - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s: cy_as_usb_connect message " - "sent\n", __func__); - #endif -} - -/* - * When a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - cyasgadget *dev = cy_as_gadget_controller; - int retval; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called driver=0x%x\n", - __func__, (unsigned int) driver); - #endif - - /* insist on high speed support from the driver, since - * "must not be used in normal operation" - */ - if (!driver - || !bind - || !driver->unbind - || !driver->setup) - return -EINVAL; - - if (!dev) - return -ENODEV; - - if (dev->driver) - return -EBUSY; - - /* hook up the driver ... */ - dev->softconnect = 1; - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - /* Do the needful */ - cyas_usb_reset(dev); /* External usb */ - cyas_usb_reinit(dev); /* Internal */ - - retval = bind(&dev->gadget); - if (retval) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("%s bind to driver %s --> %d\n", - __func__, driver->driver.name, retval); - #endif - - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - - /* ... then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - */ - cyas_ep0_start(dev); - - return 0; -} -EXPORT_SYMBOL(usb_gadget_probe_driver); - -static void cyasgadget_nuke( - cyasgadget_ep *an_ep - ) -{ - cyasgadget *dev = cy_as_gadget_controller; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - cy_as_usb_cancel_async(dev->dev_handle, an_ep->num); - an_ep->stopped = 1; - - while (!list_empty(&an_ep->queue)) { - cyasgadget_req *an_req = list_entry - (an_ep->queue.next, cyasgadget_req, queue); - list_del_init(&an_req->queue); - an_req->req.status = -ESHUTDOWN; - an_req->req.complete(&an_ep->usb_ep_inst, &an_req->req); - } -} - -static void cyasgadget_stop_activity( - cyasgadget *dev, - struct usb_gadget_driver *driver - ) -{ - int index; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - /* don't disconnect if it's not connected */ - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - if (spin_is_locked(&dev->lock)) - spin_unlock(&dev->lock); - - /* Stop hardware; prevent new request submissions; - * and kill any outstanding requests. - */ - cy_as_usb_disconnect(dev->dev_handle, 0, 0); - - for (index = 3; index <= 7; index += 2) { - cyasgadget_ep *an_ep_p = &dev->an_gadget_ep[index]; - cyasgadget_nuke(an_ep_p); - } - - for (index = 9; index <= 15; index++) { - cyasgadget_ep *an_ep_p = &dev->an_gadget_ep[index]; - cyasgadget_nuke(an_ep_p); - } - - /* report disconnect; the driver is already quiesced */ - if (driver) - driver->disconnect(&dev->gadget); - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("cy_as_usb_disconnect returned success"); - #endif - - /* Stop Usb */ - cy_as_usb_stop(dev->dev_handle, 0, 0); - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("cy_as_usb_stop returned success"); - #endif -} - -int usb_gadget_unregister_driver( - struct usb_gadget_driver *driver - ) -{ - cyasgadget *dev = cy_as_gadget_controller; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - if (!dev) - return -ENODEV; - - if (!driver || driver != dev->driver) - return -EINVAL; - - cyasgadget_stop_activity(dev, driver); - - driver->unbind(&dev->gadget); - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("unregistered driver '%s'\n", - driver->driver.name); - #endif - - return 0; -} -EXPORT_SYMBOL(usb_gadget_unregister_driver); - -static void cyas_gadget_release( - struct device *_dev - ) -{ - cyasgadget *dev = dev_get_drvdata(_dev); - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>%s called\n", __func__); - #endif - - kfree(dev); -} - -/* DeInitialize gadget driver */ -static void cyasgadget_deinit( - cyasgadget *cy_as_dev - ) -{ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget deinitialize called\n"); - #endif - - if (!cy_as_dev) { - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget_deinit: " - "invalid cyasgadget device\n"); - #endif - return; - } - - if (cy_as_dev->driver) { - /* should have been done already by driver model core */ - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1> cy_as_gadget: '%s' " - "is still registered\n", - cy_as_dev->driver->driver.name); - #endif - usb_gadget_unregister_driver(cy_as_dev->driver); - } - - kfree(cy_as_dev); - cy_as_gadget_controller = NULL; -} - -/* Initialize gadget driver */ -static int cyasgadget_initialize(void) -{ - cyasgadget *cy_as_dev = 0; - int retval = 0; - - #ifndef WESTBRIDGE_NDEBUG - cy_as_hal_print_message("<1>_cy_as_gadget [V1.1] initialize called\n"); - #endif - - if (cy_as_gadget_controller != 0) { - cy_as_hal_print_message("<1> cy_as_gadget: the device has " - "already been initilaized. ignoring\n"); - return -EBUSY; - } - - cy_as_dev = kzalloc(sizeof(cyasgadget), GFP_ATOMIC); - if (cy_as_dev == NULL) { - cy_as_hal_print_message("<1> cy_as_gadget: memory " - "allocation failed\n"); - return -ENOMEM; - } - - spin_lock_init(&cy_as_dev->lock); - cy_as_dev->gadget.ops = &cyasgadget_ops; - cy_as_dev->gadget.is_dualspeed = 1; - - /* the "gadget" abstracts/virtualizes the controller */ - /*strcpy(cy_as_dev->gadget.dev.bus_id, "cyasgadget");*/ - cy_as_dev->gadget.dev.release = cyas_gadget_release; - cy_as_dev->gadget.name = cy_as_driver_name; - - /* Get the device handle */ - cy_as_dev->dev_handle = cyasdevice_getdevhandle(); - if (0 == cy_as_dev->dev_handle) { - #ifndef NDEBUG - cy_as_hal_print_message("<1> cy_as_gadget: " - "no west bridge device\n"); - #endif - retval = -EFAULT; - goto done; - } - - /* We are done now */ - cy_as_gadget_controller = cy_as_dev; - return 0; - -/* - * in case of an error - */ -done: - if (cy_as_dev) - cyasgadget_deinit(cy_as_dev); - - return retval; -} - -static int __init cyas_init(void) -{ - int init_res = 0; - - init_res = cyasgadget_initialize(); - - if (init_res != 0) { - printk(KERN_WARNING "<1> gadget ctl instance " - "init error:%d\n", init_res); - if (init_res > 0) { - /* force -E/0 linux convention */ - init_res = init_res * -1; - } - } - - return init_res; -} -module_init(cyas_init); - -static void __exit cyas_cleanup(void) -{ - if (cy_as_gadget_controller != NULL) - cyasgadget_deinit(cy_as_gadget_controller); -} -module_exit(cyas_cleanup); - - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(CY_AS_DRIVER_DESC); -MODULE_AUTHOR("cypress semiconductor"); - -/*[]*/ |