static long rmnet_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) { struct rmnet_ctrl_qti_port *port = fp->private_data; int val, ret = 0; pr_debug("%s: Received command %d", __func__, cmd); if (rmnet_ctrl_lock(&port->ioctl_excl)) return -EBUSY; switch (cmd) { case FRMNET_CTRL_GET_LINE_STATE: val = atomic_read(&port->line_state); ret = copy_to_user((void __user *)arg, &val, sizeof(val)); if (ret) { pr_err("copying to user space failed"); ret = -EFAULT; } pr_debug("%s: Sent line_state: %d", __func__, atomic_read(&port->line_state)); break; default: pr_err("wrong parameter"); ret = -EINVAL; } rmnet_ctrl_unlock(&port->ioctl_excl); return ret; }
static int rmnet_ctrl_open(struct inode *ip, struct file *fp) { unsigned long flags; struct rmnet_ctrl_qti_port *port = container_of(fp->private_data, struct rmnet_ctrl_qti_port, rmnet_device); pr_debug("Open rmnet_ctrl_qti device file name=%s(index=%d)\n", port->name, port->index); if (rmnet_ctrl_lock(&port->open_excl)) { pr_err("Already opened\n"); return -EBUSY; } spin_lock_irqsave(&port->lock, flags); port->is_open = true; spin_unlock_irqrestore(&port->lock, flags); return 0; }
static ssize_t rmnet_ctrl_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) { struct rmnet_ctrl_qti_port *port = fp->private_data; void *kbuf; unsigned long flags; int ret = 0; pr_debug("%s: Enter(%d) port_index=%d", __func__, count, port->index); if (!count) { pr_debug("zero length ctrl pkt\n"); return -EINVAL; } if (count > MAX_QTI_PKT_SIZE) { pr_debug("given pkt size too big:%d > max_pkt_size:%d\n", count, MAX_QTI_PKT_SIZE); return -EINVAL; } if (rmnet_ctrl_lock(&port->write_excl)) { pr_err("Previous writing not finished yet\n"); return -EBUSY; } if (!atomic_read(&port->connected)) { pr_debug("USB cable not connected\n"); rmnet_ctrl_unlock(&port->write_excl); return -EPIPE; } kbuf = kmalloc(count, GFP_KERNEL); if (!kbuf) { pr_err("failed to allocate ctrl pkt\n"); rmnet_ctrl_unlock(&port->write_excl); return -ENOMEM; } ret = copy_from_user(kbuf, buf, count); if (ret) { pr_err("copy_from_user failed err:%d\n", ret); kfree(kbuf); rmnet_ctrl_unlock(&port->write_excl); return -EFAULT; } spin_lock_irqsave(&port->lock, flags); if (port->port_usb && port->port_usb->send_cpkt_response) { ret = port->port_usb->send_cpkt_response(port->port_usb, kbuf, count); if (ret) { pr_err("failed to send ctrl packet. error=%d\n", ret); spin_unlock_irqrestore(&port->lock, flags); kfree(kbuf); rmnet_ctrl_unlock(&port->write_excl); return ret; } } else { pr_err("send_cpkt_response callback is NULL\n"); spin_unlock_irqrestore(&port->lock, flags); kfree(kbuf); rmnet_ctrl_unlock(&port->write_excl); return -EINVAL; } spin_unlock_irqrestore(&port->lock, flags); kfree(kbuf); rmnet_ctrl_unlock(&port->write_excl); pr_debug("%s: Exit(%d)", __func__, count); return count; }
static ssize_t rmnet_ctrl_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { struct rmnet_ctrl_qti_port *port = fp->private_data; struct rmnet_ctrl_pkt *cpkt = NULL; unsigned long flags; int ret = 0; pr_debug("%s: Enter(%d)\n", __func__, count); if (count > MAX_QTI_PKT_SIZE) { pr_err("Buffer size is too big %d, should be at most %d\n", count, MAX_QTI_PKT_SIZE); return -EINVAL; } if (rmnet_ctrl_lock(&port->read_excl)) { pr_err("Previous reading is not finished yet\n"); return -EBUSY; } /* block until a new packet is available */ do { spin_lock_irqsave(&port->lock, flags); if (!list_empty(&port->cpkt_req_q)) break; spin_unlock_irqrestore(&port->lock, flags); pr_debug("%s: Requests list is empty. Wait.\n", __func__); ret = wait_event_interruptible(port->read_wq, !list_empty(&port->cpkt_req_q)); if (ret < 0) { pr_debug("Waiting failed\n"); rmnet_ctrl_unlock(&port->read_excl); return -ERESTARTSYS; } } while (1); cpkt = list_first_entry(&port->cpkt_req_q, struct rmnet_ctrl_pkt, list); list_del(&cpkt->list); spin_unlock_irqrestore(&port->lock, flags); if (cpkt->len > count) { pr_err("cpkt size too big:%d > buf size:%d\n", cpkt->len, count); rmnet_ctrl_unlock(&port->read_excl); free_rmnet_ctrl_pkt(cpkt); return -ENOMEM; } pr_debug("%s: cpkt size:%d\n", __func__, cpkt->len); rmnet_ctrl_unlock(&port->read_excl); ret = copy_to_user(buf, cpkt->buf, cpkt->len); if (ret) { pr_err("copy_to_user failed: err %d\n", ret); ret = -EFAULT; } else { pr_debug("%s: copied %d bytes to user\n", __func__, cpkt->len); ret = cpkt->len; } free_rmnet_ctrl_pkt(cpkt); return ret; }
static long rmnet_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg) { struct rmnet_ctrl_qti_port *port = container_of(fp->private_data, struct rmnet_ctrl_qti_port, rmnet_device); struct grmnet *gr = NULL; struct ep_info info; int val, ret = 0; pr_debug("%s: Received command %d", __func__, cmd); if (rmnet_ctrl_lock(&port->ioctl_excl)) return -EBUSY; switch (cmd) { case FRMNET_CTRL_MODEM_OFFLINE: if (port && port->port_usb) gr = port->port_usb; if (gr && gr->disconnect) gr->disconnect(gr); break; case FRMNET_CTRL_MODEM_ONLINE: if (port && port->port_usb) gr = port->port_usb; if (gr && gr->connect) gr->connect(gr); break; case FRMNET_CTRL_GET_LINE_STATE: val = atomic_read(&port->line_state); ret = copy_to_user((void __user *)arg, &val, sizeof(val)); if (ret) { pr_err("copying to user space failed"); ret = -EFAULT; } pr_debug("%s: Sent line_state: %d", __func__, atomic_read(&port->line_state)); break; case FRMNET_CTRL_EP_LOOKUP: val = atomic_read(&port->connected); if (!val) { pr_err("EP_LOOKUP failed - not connected"); ret = -EAGAIN; break; } if (port->ipa_prod_idx == -1 || port->ipa_cons_idx == -1) { pr_err("EP_LOOKUP failed - ipa pipes were not updated"); ret = -EAGAIN; break; } info.ph_ep_info.ep_type = DATA_EP_TYPE_HSUSB; info.ph_ep_info.peripheral_iface_id = port->intf; info.ipa_ep_pair.cons_pipe_num = port->ipa_cons_idx; info.ipa_ep_pair.prod_pipe_num = port->ipa_prod_idx; ret = copy_to_user((void __user *)arg, &info, sizeof(info)); if (ret) { pr_err("copying to user space failed"); ret = -EFAULT; } break; default: pr_err("wrong parameter"); ret = -EINVAL; } rmnet_ctrl_unlock(&port->ioctl_excl); return ret; }