cregit-Linux how code gets into the kernel

Release 4.11 drivers/staging/gdm724x/gdm_mux.c

/*
 * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * 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.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/slab.h>
#include <linux/usb/cdc.h>

#include "gdm_mux.h"


static u16 packet_type[TTY_MAX_COUNT] = {0xF011, 0xF010};


#define USB_DEVICE_CDC_DATA(vid, pid) \
	.match_flags = \
                USB_DEVICE_ID_MATCH_DEVICE |\
                USB_DEVICE_ID_MATCH_INT_CLASS |\
                USB_DEVICE_ID_MATCH_INT_SUBCLASS,\
        .idVendor = vid,\
        .idProduct = pid,\
        .bInterfaceClass = USB_CLASS_COMM,\
        .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM


static const struct usb_device_id id_table[] = {
	{ USB_DEVICE_CDC_DATA(0x1076, 0x8000) }, /* GCT GDM7240 */
	{ USB_DEVICE_CDC_DATA(0x1076, 0x8f00) }, /* GCT GDM7243 */
	{ USB_DEVICE_CDC_DATA(0x1076, 0x9000) }, /* GCT GDM7243 */
	{ USB_DEVICE_CDC_DATA(0x1d74, 0x2300) }, /* LGIT Phoenix */
	{}
};

MODULE_DEVICE_TABLE(usb, id_table);


static int packet_type_to_index(u16 packetType) { int i; for (i = 0; i < TTY_MAX_COUNT; i++) { if (packet_type[i] == packetType) return i; } return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang4297.67%150.00%
Valentina Manea12.33%150.00%
Total43100.00%2100.00%


static struct mux_tx *alloc_mux_tx(int len) { struct mux_tx *t = NULL; t = kzalloc(sizeof(*t), GFP_ATOMIC); if (!t) return NULL; t->urb = usb_alloc_urb(0, GFP_ATOMIC); t->buf = kmalloc(MUX_TX_MAX_SIZE, GFP_ATOMIC); if (!t->urb || !t->buf) { usb_free_urb(t->urb); kfree(t->buf); kfree(t); return NULL; } return t; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang9898.00%150.00%
Ioana Ciornei22.00%150.00%
Total100100.00%2100.00%


static void free_mux_tx(struct mux_tx *t) { if (t) { usb_free_urb(t->urb); kfree(t->buf); kfree(t); } }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang36100.00%1100.00%
Total36100.00%1100.00%


static struct mux_rx *alloc_mux_rx(void) { struct mux_rx *r = NULL; r = kzalloc(sizeof(*r), GFP_KERNEL); if (!r) return NULL; r->urb = usb_alloc_urb(0, GFP_KERNEL); r->buf = kmalloc(MUX_RX_MAX_SIZE, GFP_KERNEL); if (!r->urb || !r->buf) { usb_free_urb(r->urb); kfree(r->buf); kfree(r); return NULL; } return r; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang9494.95%133.33%
Alexey Khoroshilov33.03%133.33%
Ioana Ciornei22.02%133.33%
Total99100.00%3100.00%


static void free_mux_rx(struct mux_rx *r) { if (r) { usb_free_urb(r->urb); kfree(r->buf); kfree(r); } }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang36100.00%1100.00%
Total36100.00%1100.00%


static struct mux_rx *get_rx_struct(struct rx_cxt *rx) { struct mux_rx *r; unsigned long flags; spin_lock_irqsave(&rx->free_list_lock, flags); if (list_empty(&rx->rx_free_list)) { spin_unlock_irqrestore(&rx->free_list_lock, flags); return NULL; } r = list_entry(rx->rx_free_list.prev, struct mux_rx, free_list); list_del(&r->free_list); spin_unlock_irqrestore(&rx->free_list_lock, flags); return r; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang94100.00%1100.00%
Total94100.00%1100.00%


static void put_rx_struct(struct rx_cxt *rx, struct mux_rx *r) { unsigned long flags; spin_lock_irqsave(&rx->free_list_lock, flags); list_add_tail(&r->free_list, &rx->rx_free_list); spin_unlock_irqrestore(&rx->free_list_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang53100.00%1100.00%
Total53100.00%1100.00%


static int up_to_host(struct mux_rx *r) { struct mux_dev *mux_dev = r->mux_dev; struct mux_pkt_header *mux_header; unsigned int start_flag; unsigned int payload_size; unsigned short packet_type; int total_len; u32 packet_size_sum = r->offset; int index; int ret = TO_HOST_INVALID_PACKET; int len = r->len; while (1) { mux_header = (struct mux_pkt_header *)(r->buf + packet_size_sum); start_flag = __le32_to_cpu(mux_header->start_flag); payload_size = __le32_to_cpu(mux_header->payload_size); packet_type = __le16_to_cpu(mux_header->packet_type); if (start_flag != START_FLAG) { pr_err("invalid START_FLAG %x\n", start_flag); break; } total_len = ALIGN(MUX_HEADER_SIZE + payload_size, 4); if (len - packet_size_sum < total_len) { pr_err("invalid payload : %d %d %04x\n", payload_size, len, packet_type); break; } index = packet_type_to_index(packet_type); if (index < 0) { pr_err("invalid index %d\n", index); break; } ret = r->callback(mux_header->data, payload_size, index, mux_dev->tty_dev, RECV_PACKET_PROCESS_CONTINUE ); if (ret == TO_HOST_BUFFER_REQUEST_FAIL) { r->offset += packet_size_sum; break; } packet_size_sum += total_len; if (len - packet_size_sum <= MUX_HEADER_SIZE + 2) { ret = r->callback(NULL, 0, index, mux_dev->tty_dev, RECV_PACKET_PROCESS_COMPLETE ); break; } } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang24394.55%240.00%
Joe Perches62.33%120.00%
Rashika Kheria41.56%120.00%
SÅ‚awomir Demeszko41.56%120.00%
Total257100.00%5100.00%


static void do_rx(struct work_struct *work) { struct mux_dev *mux_dev = container_of(work, struct mux_dev, work_rx.work); struct mux_rx *r; struct rx_cxt *rx = &mux_dev->rx; unsigned long flags; int ret = 0; while (1) { spin_lock_irqsave(&rx->to_host_lock, flags); if (list_empty(&rx->to_host_list)) { spin_unlock_irqrestore(&rx->to_host_lock, flags); break; } r = list_entry(rx->to_host_list.next, struct mux_rx, to_host_list); list_del(&r->to_host_list); spin_unlock_irqrestore(&rx->to_host_lock, flags); ret = up_to_host(r); if (ret == TO_HOST_BUFFER_REQUEST_FAIL) pr_err("failed to send mux data to host\n"); else put_rx_struct(rx, r); } }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang14998.68%150.00%
Joe Perches21.32%150.00%
Total151100.00%2100.00%


static void remove_rx_submit_list(struct mux_rx *r, struct rx_cxt *rx) { unsigned long flags; struct mux_rx *r_remove, *r_remove_next; spin_lock_irqsave(&rx->submit_list_lock, flags); list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list) { if (r == r_remove) list_del(&r->rx_submit_list); } spin_unlock_irqrestore(&rx->submit_list_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang74100.00%1100.00%
Total74100.00%1100.00%


static void gdm_mux_rcv_complete(struct urb *urb) { struct mux_rx *r = urb->context; struct mux_dev *mux_dev = r->mux_dev; struct rx_cxt *rx = &mux_dev->rx; unsigned long flags; remove_rx_submit_list(r, rx); if (urb->status) { if (mux_dev->usb_state == PM_NORMAL) dev_err(&urb->dev->dev, "%s: urb status error %d\n", __func__, urb->status); put_rx_struct(rx, r); } else { r->len = r->urb->actual_length; spin_lock_irqsave(&rx->to_host_lock, flags); list_add_tail(&r->to_host_list, &rx->to_host_list); schedule_work(&mux_dev->work_rx.work); spin_unlock_irqrestore(&rx->to_host_lock, flags); } }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang13591.84%125.00%
Haneen Mohammed85.44%125.00%
Joe Perches32.04%125.00%
Amitoj Kaur Chawla10.68%125.00%
Total147100.00%4100.00%


static int gdm_mux_recv(void *priv_dev, int (*cb)(void *data, int len, int tty_index, struct tty_dev *tty_dev, int complete)) { struct mux_dev *mux_dev = priv_dev; struct usb_device *usbdev = mux_dev->usbdev; struct mux_rx *r; struct rx_cxt *rx = &mux_dev->rx; unsigned long flags; int ret; if (!usbdev) { pr_err("device is disconnected\n"); return -ENODEV; } r = get_rx_struct(rx); if (!r) { pr_err("get_rx_struct fail\n"); return -ENOMEM; } r->offset = 0; r->mux_dev = (void *)mux_dev; r->callback = cb; mux_dev->rx_cb = cb; usb_fill_bulk_urb(r->urb, usbdev, usb_rcvbulkpipe(usbdev, 0x86), r->buf, MUX_RX_MAX_SIZE, gdm_mux_rcv_complete, r); spin_lock_irqsave(&rx->submit_list_lock, flags); list_add_tail(&r->rx_submit_list, &rx->rx_submit_list); spin_unlock_irqrestore(&rx->submit_list_lock, flags); ret = usb_submit_urb(r->urb, GFP_KERNEL); if (ret) { spin_lock_irqsave(&rx->submit_list_lock, flags); list_del(&r->rx_submit_list); spin_unlock_irqrestore(&rx->submit_list_lock, flags); put_rx_struct(rx, r); pr_err("usb_submit_urb ret=%d\n", ret); } usb_mark_last_busy(usbdev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang26097.74%266.67%
Joe Perches62.26%133.33%
Total266100.00%3100.00%


static void gdm_mux_send_complete(struct urb *urb) { struct mux_tx *t = urb->context; if (urb->status == -ECONNRESET) { dev_info(&urb->dev->dev, "CONNRESET\n"); free_mux_tx(t); return; } if (t->callback) t->callback(t->cb_data); free_mux_tx(t); }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang6086.96%133.33%
Haneen Mohammed811.59%133.33%
Joe Perches11.45%133.33%
Total69100.00%3100.00%


static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index, void (*cb)(void *data), void *cb_data) { struct mux_dev *mux_dev = priv_dev; struct usb_device *usbdev = mux_dev->usbdev; struct mux_pkt_header *mux_header; struct mux_tx *t = NULL; static u32 seq_num = 1; int total_len; int ret; unsigned long flags; if (mux_dev->usb_state == PM_SUSPEND) { ret = usb_autopm_get_interface(mux_dev->intf); if (!ret) usb_autopm_put_interface(mux_dev->intf); } spin_lock_irqsave(&mux_dev->write_lock, flags); total_len = ALIGN(MUX_HEADER_SIZE + len, 4); t = alloc_mux_tx(total_len); if (!t) { pr_err("alloc_mux_tx fail\n"); spin_unlock_irqrestore(&mux_dev->write_lock, flags); return -ENOMEM; } mux_header = (struct mux_pkt_header *)t->buf; mux_header->start_flag = __cpu_to_le32(START_FLAG); mux_header->seq_num = __cpu_to_le32(seq_num++); mux_header->payload_size = __cpu_to_le32((u32)len); mux_header->packet_type = __cpu_to_le16(packet_type[tty_index]); memcpy(t->buf + MUX_HEADER_SIZE, data, len); memset(t->buf + MUX_HEADER_SIZE + len, 0, total_len - MUX_HEADER_SIZE - len); t->len = total_len; t->callback = cb; t->cb_data = cb_data; usb_fill_bulk_urb(t->urb, usbdev, usb_sndbulkpipe(usbdev, 5), t->buf, total_len, gdm_mux_send_complete, t); ret = usb_submit_urb(t->urb, GFP_ATOMIC); spin_unlock_irqrestore(&mux_dev->write_lock, flags); if (ret) pr_err("usb_submit_urb Error: %d\n", ret); usb_mark_last_busy(usbdev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang31995.51%120.00%
SÅ‚awomir Demeszko61.80%120.00%
Joe Perches41.20%120.00%
Rashika Kheria41.20%120.00%
Wei Yongjun10.30%120.00%
Total334100.00%5100.00%


static int gdm_mux_send_control(void *priv_dev, int request, int value, void *buf, int len) { struct mux_dev *mux_dev = priv_dev; struct usb_device *usbdev = mux_dev->usbdev; int ret; ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), request, USB_RT_ACM, value, 2, buf, len, 5000 ); if (ret < 0) pr_err("usb_control_msg error: %d\n", ret); return min(ret, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang8593.41%133.33%
Bhumika Goyal44.40%133.33%
Joe Perches22.20%133.33%
Total91100.00%3100.00%


static void release_usb(struct mux_dev *mux_dev) { struct rx_cxt *rx = &mux_dev->rx; struct mux_rx *r, *r_next; unsigned long flags; cancel_delayed_work(&mux_dev->work_rx); spin_lock_irqsave(&rx->submit_list_lock, flags); list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) { spin_unlock_irqrestore(&rx->submit_list_lock, flags); usb_kill_urb(r->urb); spin_lock_irqsave(&rx->submit_list_lock, flags); } spin_unlock_irqrestore(&rx->submit_list_lock, flags); spin_lock_irqsave(&rx->free_list_lock, flags); list_for_each_entry_safe(r, r_next, &rx->rx_free_list, free_list) { list_del(&r->free_list); free_mux_rx(r); } spin_unlock_irqrestore(&rx->free_list_lock, flags); spin_lock_irqsave(&rx->to_host_lock, flags); list_for_each_entry_safe(r, r_next, &rx->to_host_list, to_host_list) { if (r->mux_dev == (void *)mux_dev) { list_del(&r->to_host_list); free_mux_rx(r); } } spin_unlock_irqrestore(&rx->to_host_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang204100.00%1100.00%
Total204100.00%1100.00%


static int init_usb(struct mux_dev *mux_dev) { struct mux_rx *r; struct rx_cxt *rx = &mux_dev->rx; int ret = 0; int i; spin_lock_init(&mux_dev->write_lock); INIT_LIST_HEAD(&rx->to_host_list); INIT_LIST_HEAD(&rx->rx_submit_list); INIT_LIST_HEAD(&rx->rx_free_list); spin_lock_init(&rx->to_host_lock); spin_lock_init(&rx->submit_list_lock); spin_lock_init(&rx->free_list_lock); for (i = 0; i < MAX_ISSUE_NUM * 2; i++) { r = alloc_mux_rx(); if (!r) { ret = -ENOMEM; break; } list_add(&r->free_list, &rx->rx_free_list); } INIT_DELAYED_WORK(&mux_dev->work_rx, do_rx); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang15099.34%150.00%
Ioana Ciornei10.66%150.00%
Total151100.00%2100.00%


static int gdm_mux_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct mux_dev *mux_dev; struct tty_dev *tty_dev; u16 idVendor, idProduct; int bInterfaceNumber; int ret; int i; struct usb_device *usbdev = interface_to_usbdev(intf); bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; idVendor = __le16_to_cpu(usbdev->descriptor.idVendor); idProduct = __le16_to_cpu(usbdev->descriptor.idProduct); pr_info("mux vid = 0x%04x pid = 0x%04x\n", idVendor, idProduct); if (bInterfaceNumber != 2) return -ENODEV; mux_dev = kzalloc(sizeof(*mux_dev), GFP_KERNEL); if (!mux_dev) return -ENOMEM; tty_dev = kzalloc(sizeof(*tty_dev), GFP_KERNEL); if (!tty_dev) { ret = -ENOMEM; goto err_free_mux; } mux_dev->usbdev = usbdev; mux_dev->control_intf = intf; ret = init_usb(mux_dev); if (ret) goto err_free_usb; tty_dev->priv_dev = (void *)mux_dev; tty_dev->send_func = gdm_mux_send; tty_dev->recv_func = gdm_mux_recv; tty_dev->send_control = gdm_mux_send_control; ret = register_lte_tty_device(tty_dev, &intf->dev); if (ret) goto err_unregister_tty; for (i = 0; i < TTY_MAX_COUNT; i++) mux_dev->tty_dev = tty_dev; mux_dev->intf = intf; mux_dev->usb_state = PM_NORMAL; usb_get_dev(usbdev); usb_set_intfdata(intf, tty_dev); return 0; err_unregister_tty: unregister_lte_tty_device(tty_dev); err_free_usb: release_usb(mux_dev); kfree(tty_dev); err_free_mux: kfree(mux_dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang25585.00%233.33%
Dan Carpenter3812.67%116.67%
Alexey Khoroshilov31.00%116.67%
Joe Perches20.67%116.67%
Ioana Ciornei20.67%116.67%
Total300100.00%6100.00%


static void gdm_mux_disconnect(struct usb_interface *intf) { struct tty_dev *tty_dev; struct mux_dev *mux_dev; struct usb_device *usbdev = interface_to_usbdev(intf); tty_dev = usb_get_intfdata(intf); mux_dev = tty_dev->priv_dev; release_usb(mux_dev); unregister_lte_tty_device(tty_dev); kfree(mux_dev); kfree(tty_dev); usb_put_dev(usbdev); }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang69100.00%1100.00%
Total69100.00%1100.00%


static int gdm_mux_suspend(struct usb_interface *intf, pm_message_t pm_msg) { struct tty_dev *tty_dev; struct mux_dev *mux_dev; struct rx_cxt *rx; struct mux_rx *r, *r_next; unsigned long flags; tty_dev = usb_get_intfdata(intf); mux_dev = tty_dev->priv_dev; rx = &mux_dev->rx; cancel_work_sync(&mux_dev->work_rx.work); if (mux_dev->usb_state != PM_NORMAL) { dev_err(intf->usb_dev, "usb suspend - invalid state\n"); return -1; } mux_dev->usb_state = PM_SUSPEND; spin_lock_irqsave(&rx->submit_list_lock, flags); list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) { spin_unlock_irqrestore(&rx->submit_list_lock, flags); usb_kill_urb(r->urb); spin_lock_irqsave(&rx->submit_list_lock, flags); } spin_unlock_irqrestore(&rx->submit_list_lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang14690.12%125.00%
Amitoj Kaur Chawla106.17%125.00%
Haneen Mohammed53.09%125.00%
Joe Perches10.62%125.00%
Total162100.00%4100.00%


static int gdm_mux_resume(struct usb_interface *intf) { struct tty_dev *tty_dev; struct mux_dev *mux_dev; u8 i; tty_dev = usb_get_intfdata(intf); mux_dev = tty_dev->priv_dev; if (mux_dev->usb_state != PM_SUSPEND) { dev_err(intf->usb_dev, "usb resume - invalid state\n"); return -1; } mux_dev->usb_state = PM_NORMAL; for (i = 0; i < MAX_ISSUE_NUM; i++) gdm_mux_recv(mux_dev, mux_dev->rx_cb); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang8593.41%133.33%
Haneen Mohammed55.49%133.33%
Joe Perches11.10%133.33%
Total91100.00%3100.00%

static struct usb_driver gdm_mux_driver = { .name = "gdm_mux", .probe = gdm_mux_probe, .disconnect = gdm_mux_disconnect, .id_table = id_table, .supports_autosuspend = 1, .suspend = gdm_mux_suspend, .resume = gdm_mux_resume, .reset_resume = gdm_mux_resume, };
static int __init gdm_usb_mux_init(void) { register_lte_tty_driver(); return usb_register(&gdm_mux_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang19100.00%1100.00%
Total19100.00%1100.00%


static void __exit gdm_usb_mux_exit(void) { unregister_lte_tty_driver(); usb_deregister(&gdm_mux_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Won Kang18100.00%1100.00%
Total18100.00%1100.00%

module_init(gdm_usb_mux_init); module_exit(gdm_usb_mux_exit); MODULE_DESCRIPTION("GCT LTE TTY Device Driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Won Kang290695.19%212.50%
Dan Carpenter381.24%16.25%
Joe Perches351.15%16.25%
Haneen Mohammed260.85%212.50%
Amitoj Kaur Chawla110.36%16.25%
SÅ‚awomir Demeszko100.33%16.25%
Rashika Kheria80.26%16.25%
Ioana Ciornei70.23%212.50%
Alexey Khoroshilov60.20%212.50%
Bhumika Goyal40.13%16.25%
Valentina Manea10.03%16.25%
Wei Yongjun10.03%16.25%
Total3053100.00%16100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.