1/*
2  USB Modem Driver for Longcheer devices
3
4  Copyright (C) 2011  caoweigang <caoweigang@longcheer.net> <caowai@gmail.com>
5
6  This driver is free software; you can redistribute it and/or modify
7  it under the terms of Version 2 of the GNU General Public License as
8  published by the Free Software Foundation.
9
10*/
11
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/tty.h>
15#include <linux/module.h>
16#include <linux/usb.h>
17#include <linux/usb/serial.h>
18#include <linux/version.h>
19
20/*
21 * Driver information
22 */
23#define LCT_DRIVER_VERSION 	"v0.03"
24#define LCT_DRIVER_DESC 	"Longcheer usb modem driver"
25#define LCT_DRIVER_NAME		"Longcheer"
26#define LCT_DEVICE_DESC		"Longcheer usb modem"
27
28#define LCT_VENDOR_ID 		0x1c9e
29#define LCT_CM55_PID 		0x9e00
30#define LCT_WM6100_PID 		0x9604
31#define LCT_WM71_PID 		0x9603
32#define LCT_WM7608_PID 		0x9800
33#define LCT_WM7211_PID 		0x9605
34#define LCT_WM7211_TATA_PID 		0x9803
35
36static struct usb_device_id lct_id_table [] = {
37	{ USB_DEVICE(LCT_VENDOR_ID,LCT_CM55_PID) },
38	{ USB_DEVICE(LCT_VENDOR_ID,LCT_WM6100_PID)},
39	{ USB_DEVICE(LCT_VENDOR_ID,LCT_WM7608_PID)},
40	{ USB_DEVICE(LCT_VENDOR_ID,LCT_WM71_PID)},
41	{ USB_DEVICE(LCT_VENDOR_ID,LCT_WM7211_PID)},
42	{ USB_DEVICE(LCT_VENDOR_ID,LCT_WM7211_TATA_PID)},
43	{ }
44};
45
46MODULE_DEVICE_TABLE(usb, lct_id_table);
47
48#if	LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,31)
49static int lct_serial_open(struct tty_struct *tty,
50			struct usb_serial_port *port, struct file *filp)
51#else
52static int lct_serial_open(struct tty_struct *tty,
53			struct usb_serial_port *port)
54#endif
55{
56	struct usb_serial *serial = port->serial;
57	usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 0x22, 0x21, 3, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
58#if	LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,31)
59	return usb_serial_generic_open(tty,port,filp);
60#else
61	return usb_serial_generic_open(tty,port);
62#endif
63}
64#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30)
65static void lct_serial_close(struct tty_struct *tty,
66			struct usb_serial_port *port, struct file *filp)
67#else
68static void lct_serial_close(struct usb_serial_port *port)
69#endif
70{
71	struct usb_serial *serial = port->serial;
72	usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 0x22, 0x21, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
73
74	if (serial->dev)
75	{
76		if (serial->num_bulk_out)
77			usb_kill_urb(port->write_urb);
78		if (serial->num_bulk_in)
79			usb_kill_urb(port->read_urb);
80	}
81}
82//#endif
83
84
85static struct usb_driver lct_modem_driver = {
86	.name =	LCT_DRIVER_NAME,
87	.probe = usb_serial_probe,
88	.disconnect = usb_serial_disconnect,
89	.no_dynamic_id = 1,
90	.id_table = lct_id_table,
91};
92
93
94static struct usb_serial_driver lct_modem_device = {
95	.driver = {
96		.owner = THIS_MODULE,
97		.name =	LCT_DRIVER_NAME,
98	},
99	.description = LCT_DEVICE_DESC,
100	.id_table =	lct_id_table,
101	.usb_driver = &lct_modem_driver,
102	.num_ports  = 1,
103//#if	LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30)
104	.open = lct_serial_open,
105	.close = lct_serial_close,
106//#endif
107};
108
109static int __init lct_modem_init(void)
110{
111	int retval;
112
113	retval = usb_serial_register(&lct_modem_device);
114
115	if (retval)
116	{
117		return retval;
118	}
119
120	retval = usb_register(&lct_modem_driver);
121
122	if (retval)
123	{
124		usb_serial_deregister(&lct_modem_device);
125		return retval;
126	}
127
128	printk(LCT_DRIVER_VERSION": "LCT_DRIVER_DESC"\n");
129
130	return 0;
131}
132
133static void __exit lct_modem_exit(void)
134{
135	usb_deregister(&lct_modem_driver);
136	usb_serial_deregister(&lct_modem_device);
137}
138
139module_init(lct_modem_init);
140module_exit(lct_modem_exit);
141
142MODULE_DESCRIPTION(LCT_DRIVER_DESC);
143MODULE_VERSION(LCT_DRIVER_VERSION);
144MODULE_LICENSE("GPL");
145