You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (47 commits) usb: musb: pass configuration specifics via pdata usb: musb: fix hanging when rmmod gadget driver USB: Add MUSB and TUSB support USB: serial: remove CONFIG_USB_DEBUG from sierra and option drivers USB: Add vendor/product id of ZTE MF628 to option USB: quirk PLL power down mode USB: omap_udc: fix compilation with debug enabled usb: cdc-acm: drain writes on close usb: cdc-acm: stop dropping tx buffers usb: cdc-acm: bugfix release() usb gadget: issue notifications from ACM function usb gadget: remove needless struct members USB: sh: r8a66597-hcd: fix disconnect regression USB: isp1301: fix compilation USB: fix compiler warning fix usb-storage: unusual_devs entry for Nokia 5300 USB: cdc-acm.c: Fix compile warnings USB: BandRich BandLuxe C150/C250 HSPA Data Card Driver USB: ftdi_sio: add support for PHI Fisco data cable (FT232BM based, VID/PID 0403:e40b) usb: isp1760: don't be noisy about short packets. ...
This commit is contained in:
@@ -2560,9 +2560,6 @@ Your cooperation is appreciated.
|
||||
96 = /dev/usb/hiddev0 1st USB HID device
|
||||
...
|
||||
111 = /dev/usb/hiddev15 16th USB HID device
|
||||
112 = /dev/usb/auer0 1st auerswald ISDN device
|
||||
...
|
||||
127 = /dev/usb/auer15 16th auerswald ISDN device
|
||||
128 = /dev/usb/brlvgr0 First Braille Voyager device
|
||||
...
|
||||
131 = /dev/usb/brlvgr3 Fourth Braille Voyager device
|
||||
|
||||
@@ -105,7 +105,6 @@ Code Seq# Include File Comments
|
||||
'T' all linux/soundcard.h conflict!
|
||||
'T' all asm-i386/ioctls.h conflict!
|
||||
'U' 00-EF linux/drivers/usb/usb.h
|
||||
'U' F0-FF drivers/usb/auerswald.c
|
||||
'V' all linux/vt.h
|
||||
'W' 00-1F linux/watchdog.h conflict!
|
||||
'W' 00-1F linux/wanrouter.h conflict!
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
Auerswald USB kernel driver
|
||||
===========================
|
||||
|
||||
What is it? What can I do with it?
|
||||
==================================
|
||||
The auerswald USB kernel driver connects your linux 2.4.x
|
||||
system to the auerswald usb-enabled devices.
|
||||
|
||||
There are two types of auerswald usb devices:
|
||||
a) small PBX systems (ISDN)
|
||||
b) COMfort system telephones (ISDN)
|
||||
|
||||
The driver installation creates the devices
|
||||
/dev/usb/auer0..15. These devices carry a vendor-
|
||||
specific protocol. You may run all auerswald java
|
||||
software on it. The java software needs a native
|
||||
library "libAuerUsbJNINative.so" installed on
|
||||
your system. This library is available from
|
||||
auerswald and shipped as part of the java software.
|
||||
|
||||
You may create the devices with:
|
||||
mknod -m 666 /dev/usb/auer0 c 180 112
|
||||
...
|
||||
mknod -m 666 /dev/usb/auer15 c 180 127
|
||||
|
||||
Future plans
|
||||
============
|
||||
- Connection to ISDN4LINUX (the hisax interface)
|
||||
|
||||
The maintainer of this driver is wolfgang@iksw-muees.de
|
||||
@@ -436,7 +436,12 @@ post_reset; the USB core guarantees that this is true of internal
|
||||
suspend/resume events as well.
|
||||
|
||||
If a driver wants to block all suspend/resume calls during some
|
||||
critical section, it can simply acquire udev->pm_mutex.
|
||||
critical section, it can simply acquire udev->pm_mutex. Note that
|
||||
calls to resume may be triggered indirectly. Block IO due to memory
|
||||
allocations can make the vm subsystem resume a device. Thus while
|
||||
holding this lock you must not allocate memory with GFP_KERNEL or
|
||||
GFP_NOFS.
|
||||
|
||||
Alternatively, if the critical section might call some of the
|
||||
usb_autopm_* routines, the driver can avoid deadlock by doing:
|
||||
|
||||
|
||||
+6
-6
@@ -2928,6 +2928,12 @@ M: jirislaby@gmail.com
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
|
||||
P: Felipe Balbi
|
||||
M: felipe.balbi@nokia.com
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
|
||||
P: Andrew Gallatin
|
||||
M: gallatin@myri.com
|
||||
@@ -4196,12 +4202,6 @@ M: oliver@neukum.name
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
USB AUERSWALD DRIVER
|
||||
P: Wolfgang Muees
|
||||
M: wolfgang@iksw-muees.de
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
USB BLOCK DRIVER (UB ub)
|
||||
P: Pete Zaitcev
|
||||
M: zaitcev@redhat.com
|
||||
|
||||
@@ -317,7 +317,6 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
|
||||
printk(error, 6, status);
|
||||
return -ENODEV;
|
||||
}
|
||||
data->multipoint = 1;
|
||||
tusb_device.dev.platform_data = data;
|
||||
|
||||
/* REVISIT let the driver know what DMA channels work */
|
||||
|
||||
@@ -57,6 +57,7 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
|
||||
obj-$(CONFIG_PARIDE) += block/paride/
|
||||
obj-$(CONFIG_TC) += tc/
|
||||
obj-$(CONFIG_USB) += usb/
|
||||
obj-$(CONFIG_USB_MUSB_HDRC) += usb/musb/
|
||||
obj-$(CONFIG_PCI) += usb/
|
||||
obj-$(CONFIG_USB_GADGET) += usb/gadget/
|
||||
obj-$(CONFIG_SERIO) += input/serio/
|
||||
|
||||
@@ -1593,7 +1593,7 @@ fail1:
|
||||
if (machine_is_omap_h2()) {
|
||||
/* full speed signaling by default */
|
||||
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
|
||||
MC1_SPEED_REG);
|
||||
MC1_SPEED);
|
||||
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
|
||||
MC2_SPD_SUSP_CTRL);
|
||||
|
||||
|
||||
+4
-2
@@ -95,16 +95,18 @@ config USB
|
||||
|
||||
source "drivers/usb/core/Kconfig"
|
||||
|
||||
source "drivers/usb/mon/Kconfig"
|
||||
|
||||
source "drivers/usb/host/Kconfig"
|
||||
|
||||
source "drivers/usb/musb/Kconfig"
|
||||
|
||||
source "drivers/usb/class/Kconfig"
|
||||
|
||||
source "drivers/usb/storage/Kconfig"
|
||||
|
||||
source "drivers/usb/image/Kconfig"
|
||||
|
||||
source "drivers/usb/mon/Kconfig"
|
||||
|
||||
comment "USB port drivers"
|
||||
depends on USB
|
||||
|
||||
|
||||
@@ -602,7 +602,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
|
||||
offd = le32_to_cpu(buf[offb++]);
|
||||
if (offd >= size) {
|
||||
if (printk_ratelimit())
|
||||
usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
|
||||
usb_err(instance->usbatm, "wrong index %#x in response to cm %#x\n",
|
||||
offd, cm);
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
|
||||
+46
-40
@@ -51,6 +51,7 @@
|
||||
*/
|
||||
|
||||
#undef DEBUG
|
||||
#undef VERBOSE_DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
@@ -70,6 +71,9 @@
|
||||
|
||||
#include "cdc-acm.h"
|
||||
|
||||
|
||||
#define ACM_CLOSE_TIMEOUT 15 /* seconds to let writes drain */
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
@@ -85,6 +89,12 @@ static DEFINE_MUTEX(open_mutex);
|
||||
|
||||
#define ACM_READY(acm) (acm && acm->dev && acm->used)
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define verbose 1
|
||||
#else
|
||||
#define verbose 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Functions for ACM control messages.
|
||||
*/
|
||||
@@ -136,19 +146,17 @@ static int acm_wb_alloc(struct acm *acm)
|
||||
static int acm_wb_is_avail(struct acm *acm)
|
||||
{
|
||||
int i, n;
|
||||
unsigned long flags;
|
||||
|
||||
n = ACM_NW;
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
for (i = 0; i < ACM_NW; i++) {
|
||||
n -= acm->wb[i].use;
|
||||
}
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline int acm_wb_is_used(struct acm *acm, int wbn)
|
||||
{
|
||||
return acm->wb[wbn].use;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish write.
|
||||
*/
|
||||
@@ -157,7 +165,6 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
acm->write_ready = 1;
|
||||
wb->use = 0;
|
||||
acm->transmitting--;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
@@ -190,40 +197,25 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
|
||||
static int acm_write_start(struct acm *acm, int wbn)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct acm_wb *wb;
|
||||
struct acm_wb *wb = &acm->wb[wbn];
|
||||
int rc;
|
||||
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
if (!acm->dev) {
|
||||
wb->use = 0;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!acm->write_ready) {
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return 0; /* A white lie */
|
||||
}
|
||||
|
||||
wb = &acm->wb[wbn];
|
||||
if(acm_wb_is_avail(acm) <= 1)
|
||||
acm->write_ready = 0;
|
||||
|
||||
dbg("%s susp_count: %d", __func__, acm->susp_count);
|
||||
if (acm->susp_count) {
|
||||
acm->old_ready = acm->write_ready;
|
||||
acm->delayed_wb = wb;
|
||||
acm->write_ready = 0;
|
||||
schedule_work(&acm->waker);
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return 0; /* A white lie */
|
||||
}
|
||||
usb_mark_last_busy(acm->dev);
|
||||
|
||||
if (!acm_wb_is_used(acm, wbn)) {
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = acm_start_wb(acm, wb);
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
|
||||
@@ -488,22 +480,28 @@ urbs:
|
||||
/* data interface wrote those outgoing bytes */
|
||||
static void acm_write_bulk(struct urb *urb)
|
||||
{
|
||||
struct acm *acm;
|
||||
struct acm_wb *wb = urb->context;
|
||||
struct acm *acm = wb->instance;
|
||||
|
||||
dbg("Entering acm_write_bulk with status %d", urb->status);
|
||||
if (verbose || urb->status
|
||||
|| (urb->actual_length != urb->transfer_buffer_length))
|
||||
dev_dbg(&acm->data->dev, "tx %d/%d bytes -- > %d\n",
|
||||
urb->actual_length,
|
||||
urb->transfer_buffer_length,
|
||||
urb->status);
|
||||
|
||||
acm = wb->instance;
|
||||
acm_write_done(acm, wb);
|
||||
if (ACM_READY(acm))
|
||||
schedule_work(&acm->work);
|
||||
else
|
||||
wake_up_interruptible(&acm->drain_wait);
|
||||
}
|
||||
|
||||
static void acm_softint(struct work_struct *work)
|
||||
{
|
||||
struct acm *acm = container_of(work, struct acm, work);
|
||||
dbg("Entering acm_softint.");
|
||||
|
||||
|
||||
dev_vdbg(&acm->data->dev, "tx work\n");
|
||||
if (!ACM_READY(acm))
|
||||
return;
|
||||
tty_wakeup(acm->tty);
|
||||
@@ -512,7 +510,6 @@ static void acm_softint(struct work_struct *work)
|
||||
static void acm_waker(struct work_struct *waker)
|
||||
{
|
||||
struct acm *acm = container_of(waker, struct acm, waker);
|
||||
long flags;
|
||||
int rv;
|
||||
|
||||
rv = usb_autopm_get_interface(acm->control);
|
||||
@@ -524,9 +521,6 @@ static void acm_waker(struct work_struct *waker)
|
||||
acm_start_wb(acm, acm->delayed_wb);
|
||||
acm->delayed_wb = NULL;
|
||||
}
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
acm->write_ready = acm->old_ready;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
usb_autopm_put_interface(acm->control);
|
||||
}
|
||||
|
||||
@@ -628,6 +622,8 @@ static void acm_tty_unregister(struct acm *acm)
|
||||
kfree(acm);
|
||||
}
|
||||
|
||||
static int acm_tty_chars_in_buffer(struct tty_struct *tty);
|
||||
|
||||
static void acm_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
@@ -642,6 +638,13 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
if (acm->dev) {
|
||||
usb_autopm_get_interface(acm->control);
|
||||
acm_set_control(acm, acm->ctrlout = 0);
|
||||
|
||||
/* try letting the last writes drain naturally */
|
||||
wait_event_interruptible_timeout(acm->drain_wait,
|
||||
(ACM_NW == acm_wb_is_avail(acm))
|
||||
|| !acm->dev,
|
||||
ACM_CLOSE_TIMEOUT * HZ);
|
||||
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_kill_urb(acm->wb[i].urb);
|
||||
@@ -697,7 +700,7 @@ static int acm_tty_write_room(struct tty_struct *tty)
|
||||
* Do not let the line discipline to know that we have a reserve,
|
||||
* or it might get too enthusiastic.
|
||||
*/
|
||||
return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
|
||||
return acm_wb_is_avail(acm) ? acm->writesize : 0;
|
||||
}
|
||||
|
||||
static int acm_tty_chars_in_buffer(struct tty_struct *tty)
|
||||
@@ -1072,11 +1075,11 @@ skip_normal_probe:
|
||||
acm->urb_task.data = (unsigned long) acm;
|
||||
INIT_WORK(&acm->work, acm_softint);
|
||||
INIT_WORK(&acm->waker, acm_waker);
|
||||
init_waitqueue_head(&acm->drain_wait);
|
||||
spin_lock_init(&acm->throttle_lock);
|
||||
spin_lock_init(&acm->write_lock);
|
||||
spin_lock_init(&acm->read_lock);
|
||||
mutex_init(&acm->mutex);
|
||||
acm->write_ready = 1;
|
||||
acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
|
||||
|
||||
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||||
@@ -1108,9 +1111,11 @@ skip_normal_probe:
|
||||
rcv->instance = acm;
|
||||
}
|
||||
for (i = 0; i < num_rx_buf; i++) {
|
||||
struct acm_rb *buf = &(acm->rb[i]);
|
||||
struct acm_rb *rb = &(acm->rb[i]);
|
||||
|
||||
if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
|
||||
rb->base = usb_buffer_alloc(acm->dev, readsize,
|
||||
GFP_KERNEL, &rb->dma);
|
||||
if (!rb->base) {
|
||||
dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
|
||||
goto alloc_fail7;
|
||||
}
|
||||
@@ -1172,6 +1177,7 @@ skip_countries:
|
||||
acm_set_line(acm, &acm->line);
|
||||
|
||||
usb_driver_claim_interface(&acm_driver, data_interface, acm);
|
||||
usb_set_intfdata(data_interface, acm);
|
||||
|
||||
usb_get_intf(control_interface);
|
||||
tty_register_device(acm_tty_driver, minor, &control_interface->dev);
|
||||
@@ -1221,11 +1227,11 @@ static void acm_disconnect(struct usb_interface *intf)
|
||||
struct acm *acm = usb_get_intfdata(intf);
|
||||
struct usb_device *usb_dev = interface_to_usbdev(intf);
|
||||
|
||||
mutex_lock(&open_mutex);
|
||||
if (!acm || !acm->dev) {
|
||||
mutex_unlock(&open_mutex);
|
||||
/* sibling interface is already cleaning up */
|
||||
if (!acm)
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&open_mutex);
|
||||
if (acm->country_codes){
|
||||
device_remove_file(&acm->control->dev,
|
||||
&dev_attr_wCountryCodes);
|
||||
|
||||
@@ -106,8 +106,6 @@ struct acm {
|
||||
struct list_head spare_read_bufs;
|
||||
struct list_head filled_read_bufs;
|
||||
int write_used; /* number of non-empty write buffers */
|
||||
int write_ready; /* write urb is not running */
|
||||
int old_ready;
|
||||
int processing;
|
||||
int transmitting;
|
||||
spinlock_t write_lock;
|
||||
@@ -115,6 +113,7 @@ struct acm {
|
||||
struct usb_cdc_line_coding line; /* bits, stop, parity */
|
||||
struct work_struct work; /* work queue entry for line discipline waking up */
|
||||
struct work_struct waker;
|
||||
wait_queue_head_t drain_wait; /* close processing */
|
||||
struct tasklet_struct urb_task; /* rx processing */
|
||||
spinlock_t throttle_lock; /* synchronize throtteling and read callback */
|
||||
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
|
||||
|
||||
@@ -774,7 +774,6 @@ void usb_deregister(struct usb_driver *driver)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_deregister);
|
||||
|
||||
|
||||
/* Forced unbinding of a USB interface driver, either because
|
||||
* it doesn't support pre_reset/post_reset/reset_resume or
|
||||
* because it doesn't support suspend/resume.
|
||||
@@ -821,6 +820,8 @@ void usb_rebind_intf(struct usb_interface *intf)
|
||||
dev_warn(&intf->dev, "rebind failed: %d\n", rc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#define DO_UNBIND 0
|
||||
#define DO_REBIND 1
|
||||
|
||||
@@ -872,8 +873,6 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* Caller has locked udev's pm_mutex */
|
||||
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
|
||||
{
|
||||
|
||||
@@ -1091,8 +1091,8 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
||||
continue;
|
||||
dev_dbg(&dev->dev, "unregistering interface %s\n",
|
||||
dev_name(&interface->dev));
|
||||
device_del(&interface->dev);
|
||||
usb_remove_sysfs_intf_files(interface);
|
||||
device_del(&interface->dev);
|
||||
}
|
||||
|
||||
/* Now that the interfaces are unbound, nobody should
|
||||
|
||||
@@ -284,6 +284,16 @@ config USB_LH7A40X
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
# built in ../musb along with host support
|
||||
config USB_GADGET_MUSB_HDRC
|
||||
boolean "Inventra HDRC USB Peripheral (TI, ...)"
|
||||
depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_GADGET_SELECTED
|
||||
help
|
||||
This OTG-capable silicon IP is used in dual designs including
|
||||
the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
|
||||
|
||||
config USB_GADGET_OMAP
|
||||
boolean "OMAP USB Device Controller"
|
||||
depends on ARCH_OMAP
|
||||
|
||||
@@ -542,13 +542,14 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
|
||||
req->req.context = dum;
|
||||
req->req.complete = fifo_complete;
|
||||
|
||||
list_add_tail(&req->queue, &ep->queue);
|
||||
spin_unlock (&dum->lock);
|
||||
_req->actual = _req->length;
|
||||
_req->status = 0;
|
||||
_req->complete (_ep, _req);
|
||||
spin_lock (&dum->lock);
|
||||
}
|
||||
list_add_tail (&req->queue, &ep->queue);
|
||||
} else
|
||||
list_add_tail(&req->queue, &ep->queue);
|
||||
spin_unlock_irqrestore (&dum->lock, flags);
|
||||
|
||||
/* real hardware would likely enable transfers here, in case
|
||||
|
||||
+183
-13
@@ -47,18 +47,37 @@ struct f_acm {
|
||||
u8 ctrl_id, data_id;
|
||||
u8 port_num;
|
||||
|
||||
struct usb_descriptor_header **fs_function;
|
||||
u8 pending;
|
||||
|
||||
/* lock is mostly for pending and notify_req ... they get accessed
|
||||
* by callbacks both from tty (open/close/break) under its spinlock,
|
||||
* and notify_req.complete() which can't use that lock.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
struct acm_ep_descs fs;
|
||||
struct usb_descriptor_header **hs_function;
|
||||
struct acm_ep_descs hs;
|
||||
|
||||
struct usb_ep *notify;
|
||||
struct usb_endpoint_descriptor *notify_desc;
|
||||
struct usb_request *notify_req;
|
||||
|
||||
struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
|
||||
|
||||
/* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */
|
||||
u16 port_handshake_bits;
|
||||
#define RS232_RTS (1 << 1) /* unused with full duplex */
|
||||
#define RS232_DTR (1 << 0) /* host is ready for data r/w */
|
||||
#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */
|
||||
#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */
|
||||
|
||||
/* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */
|
||||
u16 serial_state;
|
||||
#define ACM_CTRL_OVERRUN (1 << 6)
|
||||
#define ACM_CTRL_PARITY (1 << 5)
|
||||
#define ACM_CTRL_FRAMING (1 << 4)
|
||||
#define ACM_CTRL_RI (1 << 3)
|
||||
#define ACM_CTRL_BRK (1 << 2)
|
||||
#define ACM_CTRL_DSR (1 << 1)
|
||||
#define ACM_CTRL_DCD (1 << 0)
|
||||
};
|
||||
|
||||
static inline struct f_acm *func_to_acm(struct usb_function *f)
|
||||
@@ -66,12 +85,17 @@ static inline struct f_acm *func_to_acm(struct usb_function *f)
|
||||
return container_of(f, struct f_acm, port.func);
|
||||
}
|
||||
|
||||
static inline struct f_acm *port_to_acm(struct gserial *p)
|
||||
{
|
||||
return container_of(p, struct f_acm, port);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* notification endpoint uses smallish and infrequent fixed-size messages */
|
||||
|
||||
#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
|
||||
#define GS_NOTIFY_MAXPACKET 8
|
||||
#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */
|
||||
|
||||
/* interface and class descriptors: */
|
||||
|
||||
@@ -117,7 +141,7 @@ static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
|
||||
.bLength = sizeof(acm_descriptor),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
||||
.bmCapabilities = (1 << 1),
|
||||
.bmCapabilities = USB_CDC_CAP_LINE,
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc acm_union_desc __initdata = {
|
||||
@@ -277,6 +301,11 @@ static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
||||
|
||||
/* composite driver infrastructure handles everything except
|
||||
* CDC class messages; interface activation uses set_alt().
|
||||
*
|
||||
* Note CDC spec table 4 lists the ACM request profile. It requires
|
||||
* encapsulated command support ... we don't handle any, and respond
|
||||
* to them by stalling. Options include get/set/clear comm features
|
||||
* (not that useful) and SEND_BREAK.
|
||||
*/
|
||||
switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
|
||||
|
||||
@@ -312,7 +341,7 @@ static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
||||
value = 0;
|
||||
|
||||
/* FIXME we should not allow data to flow until the
|
||||
* host sets the RS232_DTR bit; and when it clears
|
||||
* host sets the ACM_CTRL_DTR bit; and when it clears
|
||||
* that bit, we should return to that no-flow state.
|
||||
*/
|
||||
acm->port_handshake_bits = w_value;
|
||||
@@ -350,9 +379,6 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
/* we know alt == 0, so this is an activation or a reset */
|
||||
|
||||
if (intf == acm->ctrl_id) {
|
||||
/* REVISIT this may need more work when we start to
|
||||
* send notifications ...
|
||||
*/
|
||||
if (acm->notify->driver_data) {
|
||||
VDBG(cdev, "reset acm control interface %d\n", intf);
|
||||
usb_ep_disable(acm->notify);
|
||||
@@ -397,6 +423,128 @@ static void acm_disable(struct usb_function *f)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* acm_cdc_notify - issue CDC notification to host
|
||||
* @acm: wraps host to be notified
|
||||
* @type: notification type
|
||||
* @value: Refer to cdc specs, wValue field.
|
||||
* @data: data to be sent
|
||||
* @length: size of data
|
||||
* Context: irqs blocked, acm->lock held, acm_notify_req non-null
|
||||
*
|
||||
* Returns zero on sucess or a negative errno.
|
||||
*
|
||||
* See section 6.3.5 of the CDC 1.1 specification for information
|
||||
* about the only notification we issue: SerialState change.
|
||||
*/
|
||||
static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value,
|
||||
void *data, unsigned length)
|
||||
{
|
||||
struct usb_ep *ep = acm->notify;
|
||||
struct usb_request *req;
|
||||
struct usb_cdc_notification *notify;
|
||||
const unsigned len = sizeof(*notify) + length;
|
||||
void *buf;
|
||||
int status;
|
||||
|
||||
req = acm->notify_req;
|
||||
acm->notify_req = NULL;
|
||||
acm->pending = false;
|
||||
|
||||
req->length = len;
|
||||
notify = req->buf;
|
||||
buf = notify + 1;
|
||||
|
||||
notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
|
||||
| USB_RECIP_INTERFACE;
|
||||
notify->bNotificationType = type;
|
||||
notify->wValue = cpu_to_le16(value);
|
||||
notify->wIndex = cpu_to_le16(acm->ctrl_id);
|
||||
notify->wLength = cpu_to_le16(length);
|
||||
memcpy(buf, data, length);
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (status < 0) {
|
||||
ERROR(acm->port.func.config->cdev,
|
||||
"acm ttyGS%d can't notify serial state, %d\n",
|
||||
acm->port_num, status);
|
||||
acm->notify_req = req;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int acm_notify_serial_state(struct f_acm *acm)
|
||||
{
|
||||
struct usb_composite_dev *cdev = acm->port.func.config->cdev;
|
||||
int status;
|
||||
|
||||
spin_lock(&acm->lock);
|
||||
if (acm->notify_req) {
|
||||
DBG(cdev, "acm ttyGS%d serial state %04x\n",
|
||||
acm->port_num, acm->serial_state);
|
||||
status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
|
||||
0, &acm->serial_state, sizeof(acm->serial_state));
|
||||
} else {
|
||||
acm->pending = true;
|
||||
status = 0;
|
||||
}
|
||||
spin_unlock(&acm->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct f_acm *acm = req->context;
|
||||
u8 doit = false;
|
||||
|
||||
/* on this call path we do NOT hold the port spinlock,
|
||||
* which is why ACM needs its own spinlock
|
||||
*/
|
||||
spin_lock(&acm->lock);
|
||||
if (req->status != -ESHUTDOWN)
|
||||
doit = acm->pending;
|
||||
acm->notify_req = req;
|
||||
spin_unlock(&acm->lock);
|
||||
|
||||
if (doit)
|
||||
acm_notify_serial_state(acm);
|
||||
}
|
||||
|
||||
/* connect == the TTY link is open */
|
||||
|
||||
static void acm_connect(struct gserial *port)
|
||||
{
|
||||
struct f_acm *acm = port_to_acm(port);
|
||||
|
||||
acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
|
||||
acm_notify_serial_state(acm);
|
||||
}
|
||||
|
||||
static void acm_disconnect(struct gserial *port)
|
||||
{
|
||||
struct f_acm *acm = port_to_acm(port);
|
||||
|
||||
acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
|
||||
acm_notify_serial_state(acm);
|
||||
}
|
||||
|
||||
static int acm_send_break(struct gserial *port, int duration)
|
||||
{
|
||||
struct f_acm *acm = port_to_acm(port);
|
||||
u16 state;
|
||||
|
||||
state = acm->serial_state;
|
||||
state &= ~ACM_CTRL_BRK;
|
||||
if (duration)
|
||||
state |= ACM_CTRL_BRK;
|
||||
|
||||
acm->serial_state = state;
|
||||
return acm_notify_serial_state(acm);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* ACM function driver setup/binding */
|
||||
static int __init
|
||||
acm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
@@ -445,8 +593,20 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
acm->notify = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* allocate notification */
|
||||
acm->notify_req = gs_alloc_req(ep,
|
||||
sizeof(struct usb_cdc_notification) + 2,
|
||||
GFP_KERNEL);
|
||||
if (!acm->notify_req)
|
||||
goto fail;
|
||||
|
||||
acm->notify_req->complete = acm_cdc_notify_complete;
|
||||
acm->notify_req->context = acm;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(acm_fs_function);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
acm->fs.in = usb_find_endpoint(acm_fs_function,
|
||||
f->descriptors, &acm_fs_in_desc);
|
||||
@@ -478,8 +638,6 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
f->hs_descriptors, &acm_hs_notify_desc);
|
||||
}
|
||||
|
||||
/* FIXME provide a callback for triggering notifications */
|
||||
|
||||
DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
|
||||
acm->port_num,
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
@@ -488,6 +646,9 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (acm->notify_req)
|
||||
gs_free_req(acm->notify, acm->notify_req);
|
||||
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (acm->notify)
|
||||
acm->notify->driver_data = NULL;
|
||||
@@ -504,10 +665,13 @@ fail:
|
||||
static void
|
||||
acm_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_acm *acm = func_to_acm(f);
|
||||
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
kfree(func_to_acm(f));
|
||||
gs_free_req(acm->notify, acm->notify_req);
|
||||
kfree(acm);
|
||||
}
|
||||
|
||||
/* Some controllers can't support CDC ACM ... */
|
||||
@@ -571,8 +735,14 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
if (!acm)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&acm->lock);
|
||||
|
||||
acm->port_num = port_num;
|
||||
|
||||
acm->port.connect = acm_connect;
|
||||
acm->port.disconnect = acm_disconnect;
|
||||
acm->port.send_break = acm_send_break;
|
||||
|
||||
acm->port.func.name = "acm";
|
||||
acm->port.func.strings = acm_strings;
|
||||
/* descriptors are per-instance copies */
|
||||
|
||||
@@ -63,9 +63,7 @@ struct f_ecm {
|
||||
|
||||
char ethaddr[14];
|
||||
|
||||
struct usb_descriptor_header **fs_function;
|
||||
struct ecm_ep_descs fs;
|
||||
struct usb_descriptor_header **hs_function;
|
||||
struct ecm_ep_descs hs;
|
||||
|
||||
struct usb_ep *notify;
|
||||
|
||||
@@ -85,9 +85,7 @@ struct f_rndis {
|
||||
u8 ethaddr[ETH_ALEN];
|
||||
int config;
|
||||
|
||||
struct usb_descriptor_header **fs_function;
|
||||
struct rndis_ep_descs fs;
|
||||
struct usb_descriptor_header **hs_function;
|
||||
struct rndis_ep_descs hs;
|
||||
|
||||
struct usb_ep *notify;
|
||||
|
||||
@@ -36,9 +36,7 @@ struct f_gser {
|
||||
u8 data_id;
|
||||
u8 port_num;
|
||||
|
||||
struct usb_descriptor_header **fs_function;
|
||||
struct gser_descs fs;
|
||||
struct usb_descriptor_header **hs_function;
|
||||
struct gser_descs hs;
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user