2005-04-17 05:20:36 +07:00
|
|
|
/*
|
2006-07-12 11:22:58 +07:00
|
|
|
* USB Serial Converter stuff
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
2005-06-21 11:15:16 +07:00
|
|
|
* Copyright (C) 1999 - 2005
|
2005-04-17 05:20:36 +07:00
|
|
|
* Greg Kroah-Hartman (greg@kroah.com)
|
|
|
|
*
|
|
|
|
* 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
|
2006-07-12 11:22:58 +07:00
|
|
|
* the Free Software Foundation; version 2 of the License.
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __LINUX_USB_SERIAL_H
|
|
|
|
#define __LINUX_USB_SERIAL_H
|
|
|
|
|
|
|
|
#include <linux/kref.h>
|
2006-03-25 03:12:31 +07:00
|
|
|
#include <linux/mutex.h>
|
2009-05-12 03:24:09 +07:00
|
|
|
#include <linux/sysrq.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
|
2008-07-29 23:01:04 +07:00
|
|
|
#define SERIAL_TTY_MINORS 254 /* loads of devices :) */
|
|
|
|
#define SERIAL_TTY_NO_MINOR 255 /* No minor was assigned */
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
/* The maximum number of ports one device can grab at once */
|
|
|
|
#define MAX_NUM_PORTS 8
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* parity check flag */
|
|
|
|
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
|
|
|
|
2009-06-02 22:54:11 +07:00
|
|
|
enum port_dev_state {
|
|
|
|
PORT_UNREGISTERED,
|
|
|
|
PORT_REGISTERING,
|
|
|
|
PORT_REGISTERED,
|
|
|
|
PORT_UNREGISTERING,
|
|
|
|
};
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/**
|
|
|
|
* usb_serial_port: structure for the specific ports of a device.
|
|
|
|
* @serial: pointer back to the struct usb_serial owner of this port.
|
2009-04-14 20:59:51 +07:00
|
|
|
* @port: pointer to the corresponding tty_port for this port.
|
2005-04-24 02:49:16 +07:00
|
|
|
* @lock: spinlock to grab when updating portions of this structure.
|
2006-03-25 03:12:31 +07:00
|
|
|
* @mutex: mutex used to synchronize serial_open() and serial_close()
|
2005-11-29 04:16:07 +07:00
|
|
|
* access for this port.
|
2005-04-17 05:20:36 +07:00
|
|
|
* @number: the number of the port (the minor number).
|
|
|
|
* @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
|
|
|
|
* @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
|
|
|
|
* @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe
|
|
|
|
* for this port.
|
|
|
|
* @interrupt_out_buffer: pointer to the interrupt out buffer for this port.
|
|
|
|
* @interrupt_out_size: the size of the interrupt_out_buffer, in bytes.
|
|
|
|
* @interrupt_out_urb: pointer to the interrupt out struct urb for this port.
|
|
|
|
* @interrupt_out_endpointAddress: endpoint address for the interrupt out pipe
|
|
|
|
* for this port.
|
|
|
|
* @bulk_in_buffer: pointer to the bulk in buffer for this port.
|
2009-04-14 20:59:51 +07:00
|
|
|
* @bulk_in_size: the size of the bulk_in_buffer, in bytes.
|
2005-04-17 05:20:36 +07:00
|
|
|
* @read_urb: pointer to the bulk in struct urb for this port.
|
|
|
|
* @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
|
|
|
|
* port.
|
|
|
|
* @bulk_out_buffer: pointer to the bulk out buffer for this port.
|
|
|
|
* @bulk_out_size: the size of the bulk_out_buffer, in bytes.
|
|
|
|
* @write_urb: pointer to the bulk out struct urb for this port.
|
2009-04-14 20:59:51 +07:00
|
|
|
* @write_urb_busy: port`s writing status
|
2005-04-17 05:20:36 +07:00
|
|
|
* @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this
|
|
|
|
* port.
|
|
|
|
* @write_wait: a wait_queue_head_t used by the port.
|
|
|
|
* @work: work queue entry for the line discipline waking up.
|
2007-02-02 02:08:18 +07:00
|
|
|
* @throttled: nonzero if the read urb is inactive to throttle the device
|
|
|
|
* @throttle_req: nonzero if the tty wants to throttle us
|
2009-04-14 20:59:51 +07:00
|
|
|
* @console: attached usb serial console
|
|
|
|
* @dev: pointer to the serial device
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
|
|
|
* This structure is used by the usb-serial core and drivers for the specific
|
|
|
|
* ports of a device.
|
|
|
|
*/
|
|
|
|
struct usb_serial_port {
|
2008-01-31 06:21:33 +07:00
|
|
|
struct usb_serial *serial;
|
2008-07-22 17:09:07 +07:00
|
|
|
struct tty_port port;
|
2005-04-24 02:49:16 +07:00
|
|
|
spinlock_t lock;
|
2006-03-25 03:12:31 +07:00
|
|
|
struct mutex mutex;
|
2005-04-17 05:20:36 +07:00
|
|
|
unsigned char number;
|
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
unsigned char *interrupt_in_buffer;
|
|
|
|
struct urb *interrupt_in_urb;
|
2005-04-17 05:20:36 +07:00
|
|
|
__u8 interrupt_in_endpointAddress;
|
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
unsigned char *interrupt_out_buffer;
|
2005-04-17 05:20:36 +07:00
|
|
|
int interrupt_out_size;
|
2008-01-31 06:21:33 +07:00
|
|
|
struct urb *interrupt_out_urb;
|
2005-04-17 05:20:36 +07:00
|
|
|
__u8 interrupt_out_endpointAddress;
|
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
unsigned char *bulk_in_buffer;
|
2005-04-17 05:20:36 +07:00
|
|
|
int bulk_in_size;
|
2008-01-31 06:21:33 +07:00
|
|
|
struct urb *read_urb;
|
2005-04-17 05:20:36 +07:00
|
|
|
__u8 bulk_in_endpointAddress;
|
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
unsigned char *bulk_out_buffer;
|
2005-04-17 05:20:36 +07:00
|
|
|
int bulk_out_size;
|
2008-01-31 06:21:33 +07:00
|
|
|
struct urb *write_urb;
|
2005-04-24 02:49:16 +07:00
|
|
|
int write_urb_busy;
|
2005-04-17 05:20:36 +07:00
|
|
|
__u8 bulk_out_endpointAddress;
|
|
|
|
|
2009-05-12 03:24:07 +07:00
|
|
|
int tx_bytes_flight;
|
|
|
|
int urbs_in_flight;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
wait_queue_head_t write_wait;
|
|
|
|
struct work_struct work;
|
2007-02-02 02:08:18 +07:00
|
|
|
char throttled;
|
|
|
|
char throttle_req;
|
USB: usb_serial: clean tty reference in the last close
When a usb serial adapter is used as console, the usb serial console
driver bumps the open_count on the port struct used but doesn't attach
a real tty to it (only a fake one temporaly). If this port is opened later
using the regular character device interface, the open method won't
initialize the port, which is the expected, and will receive a brand new
tty struct created by tty layer, which will be stored in port->tty.
When the last close is issued, open_count won't be 0 because of the
console usage and the port->tty will still contain the old tty value. This
is the last ttyUSB<n> close so the allocated tty will be freed by the
tty layer. The usb_serial and usb_serial_port are still in use by the
console, so port_free() won't be called (serial_close() ->
usb_serial_put() -> destroy_serial() -> port_free()), so the scheduled
work (port->work, usb_serial_port_work()) will still run. And
usb_serial_port_work() does:
(...)
tty = port->tty;
if (!tty)
return;
tty_wakeup(tty);
which causes (manually copied):
Faulting instruction address: 0x6b6b6b68
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT PowerMac
Modules linked in: binfmt_misc ipv6 nfs lockd nfs_acl sunrpc dm_snapshot dm_mirror dm_mod hfsplus uinput ams input_polldev genrtc cpufreq_powersave i2c_powermac therm_adt746x snd_aoa_codec_tas snd_aoa_fabric_layout snd_aoa joydev snd_aoa_i2sbus snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd_page_alloc pmac_zilog serial_core evdev ide_cd cdrom snd appletouch soundcore snd_aoa_soundbus bcm43xx firmware_class usbhid ieee80211softmac ff_memless firewire_ohci firewire_core ieee80211 ieee80211_crypt crc_itu_t sungem sungem_phy uninorth_agp agpart ssb
NIP: 6b6b6b68 LR: c01b2108 CTR: 6b6b6b6b
REGS: c106de80 TRAP: 0400 Not tainted (2.6.24-rc2)
MSR: 40009032 <EE,ME,IR,DR> CR: 82004024 XER: 00000000
TASK = c106b4c0[5] 'events/0' THREAD: c106c000
GPR00: 6b6b6b6b c106df30 c106b4c0 c2d613a0 00009032 00000001 00001a00 00000001
GPR08: 00000008 00000000 00000000 c106c000 42004028 00000000 016ffbe0 0171a724
GPR16: 016ffcf4 00240e24 00240e70 016fee68 016ff9a4 c03046c4 c0327f50 c03046fc
GPR24: c106b6b9 c106b4c0 c101d610 c106c000 c02160fc c1eac1dc c2d613ac c2d613a0
NIP [6b6b6b68] 0x6b6b6b68
LR [c01b2108] tty_wakeup+0x6c/0x9c
Call Trace:
[c106df30] [c01b20e8] tty_wakeup+0x4c/0x9c (unreliable)
[c106df40] [c0216138] usb_serial_port_work+0x3c/0x78
[c106df50] [c00432e8] run_workqueue+0xc4/0x15c
[c106df90] [c0043798] worker_thread+0xa0/0x124
[c106dfd0] [c0048224] kthread+0x48/0x84
[c106dff0] [c00129bc] kernel_thread+0x44/0x60
Instruction dump:
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
Slab corruption: size-2048 start=c2d613a0, len=2048
Redzone: 0x9f911029d74e35b/0x9f911029d74e35b.
Last user: [<c01b16d8>](release_one_tty+0xbc/0xf4)
050: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b
Prev obj: start=c2d60b88, len=2048
Redzone: 0x9f911029d74e35b/0x9f911029d74e35b.
Last user: [<c00f30ec>](show_stat+0x410/0x428)
000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b
010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b
This patch avoids this, clearing port->tty considering if the port is
used as serial console or not
Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-11-13 03:15:02 +07:00
|
|
|
char console;
|
2009-05-12 03:24:09 +07:00
|
|
|
unsigned long sysrq; /* sysrq timeout */
|
2005-04-17 05:20:36 +07:00
|
|
|
struct device dev;
|
2009-06-02 22:54:11 +07:00
|
|
|
enum port_dev_state dev_state;
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
|
|
|
|
|
|
|
|
/* get and set the port private data pointer helper functions */
|
2008-01-31 06:21:33 +07:00
|
|
|
static inline void *usb_get_serial_port_data(struct usb_serial_port *port)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
return dev_get_drvdata(&port->dev);
|
|
|
|
}
|
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
static inline void usb_set_serial_port_data(struct usb_serial_port *port,
|
|
|
|
void *data)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
dev_set_drvdata(&port->dev, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* usb_serial - structure used by the usb-serial core for a device
|
|
|
|
* @dev: pointer to the struct usb_device for this device
|
2005-06-21 11:15:16 +07:00
|
|
|
* @type: pointer to the struct usb_serial_driver for this device
|
2005-04-17 05:20:36 +07:00
|
|
|
* @interface: pointer to the struct usb_interface for this device
|
|
|
|
* @minor: the starting minor number for this device
|
|
|
|
* @num_ports: the number of ports this device has
|
|
|
|
* @num_interrupt_in: number of interrupt in endpoints we have
|
|
|
|
* @num_interrupt_out: number of interrupt out endpoints we have
|
|
|
|
* @num_bulk_in: number of bulk in endpoints we have
|
|
|
|
* @num_bulk_out: number of bulk out endpoints we have
|
|
|
|
* @port: array of struct usb_serial_port structures for the different ports.
|
|
|
|
* @private: place to put any driver specific information that is needed. The
|
|
|
|
* usb-serial driver is required to manage this data, the usb-serial core
|
|
|
|
* will not touch this. Use usb_get_serial_data() and
|
|
|
|
* usb_set_serial_data() to access this.
|
|
|
|
*/
|
|
|
|
struct usb_serial {
|
2008-01-31 06:21:33 +07:00
|
|
|
struct usb_device *dev;
|
|
|
|
struct usb_serial_driver *type;
|
|
|
|
struct usb_interface *interface;
|
2009-02-05 22:54:25 +07:00
|
|
|
unsigned char disconnected:1;
|
|
|
|
unsigned char suspending:1;
|
2005-04-17 05:20:36 +07:00
|
|
|
unsigned char minor;
|
|
|
|
unsigned char num_ports;
|
|
|
|
unsigned char num_port_pointers;
|
|
|
|
char num_interrupt_in;
|
|
|
|
char num_interrupt_out;
|
|
|
|
char num_bulk_in;
|
|
|
|
char num_bulk_out;
|
2008-01-31 06:21:33 +07:00
|
|
|
struct usb_serial_port *port[MAX_NUM_PORTS];
|
2005-04-17 05:20:36 +07:00
|
|
|
struct kref kref;
|
2008-01-16 23:18:52 +07:00
|
|
|
struct mutex disc_mutex;
|
2008-01-31 06:21:33 +07:00
|
|
|
void *private;
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
#define to_usb_serial(d) container_of(d, struct usb_serial, kref)
|
|
|
|
|
|
|
|
/* get and set the serial private data pointer helper functions */
|
2008-01-31 06:21:33 +07:00
|
|
|
static inline void *usb_get_serial_data(struct usb_serial *serial)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
return serial->private;
|
|
|
|
}
|
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
serial->private = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-06-21 11:15:16 +07:00
|
|
|
* usb_serial_driver - describes a usb serial driver
|
2008-01-31 06:21:33 +07:00
|
|
|
* @description: pointer to a string that describes this driver. This string
|
|
|
|
* used in the syslog messages when a device is inserted or removed.
|
2005-04-17 05:20:36 +07:00
|
|
|
* @id_table: pointer to a list of usb_device_id structures that define all
|
|
|
|
* of the devices this structure can support.
|
|
|
|
* @num_ports: the number of different ports this device will have.
|
|
|
|
* @calc_num_ports: pointer to a function to determine how many ports this
|
|
|
|
* device has dynamically. It will be called after the probe()
|
|
|
|
* callback is called, but before attach()
|
|
|
|
* @probe: pointer to the driver's probe function.
|
|
|
|
* This will be called when the device is inserted into the system,
|
|
|
|
* but before the device has been fully initialized by the usb_serial
|
|
|
|
* subsystem. Use this function to download any firmware to the device,
|
|
|
|
* or any other early initialization that might be needed.
|
2006-07-12 11:22:58 +07:00
|
|
|
* Return 0 to continue on with the initialization sequence. Anything
|
2005-04-17 05:20:36 +07:00
|
|
|
* else will abort it.
|
|
|
|
* @attach: pointer to the driver's attach function.
|
|
|
|
* This will be called when the struct usb_serial structure is fully set
|
|
|
|
* set up. Do any local initialization of the device, or any private
|
|
|
|
* memory structure allocation at this point in time.
|
2009-06-02 22:53:55 +07:00
|
|
|
* @disconnect: pointer to the driver's disconnect function. This will be
|
|
|
|
* called when the device is unplugged or unbound from the driver.
|
|
|
|
* @release: pointer to the driver's release function. This will be called
|
|
|
|
* when the usb_serial data structure is about to be destroyed.
|
2006-12-18 03:50:23 +07:00
|
|
|
* @usb_driver: pointer to the struct usb_driver that controls this
|
|
|
|
* device. This is necessary to allow dynamic ids to be added to
|
|
|
|
* the driver from sysfs.
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
2005-06-21 11:15:16 +07:00
|
|
|
* This structure is defines a USB Serial driver. It provides all of
|
2005-04-17 05:20:36 +07:00
|
|
|
* the information that the USB serial core code needs. If the function
|
|
|
|
* pointers are defined, then the USB serial core code will call them when
|
|
|
|
* the corresponding tty port functions are called. If they are not
|
|
|
|
* called, the generic serial function will be used instead.
|
2005-06-21 11:15:16 +07:00
|
|
|
*
|
|
|
|
* The driver.owner field should be set to the module owner of this driver.
|
2005-06-21 11:15:16 +07:00
|
|
|
* The driver.name field should be set to the name of this driver (remember
|
|
|
|
* it will show up in sysfs, so it needs to be short and to the point.
|
2008-09-21 04:41:47 +07:00
|
|
|
* Using the module name is a good idea.)
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
2005-06-21 11:15:16 +07:00
|
|
|
struct usb_serial_driver {
|
2005-06-21 11:15:16 +07:00
|
|
|
const char *description;
|
2005-04-17 05:20:36 +07:00
|
|
|
const struct usb_device_id *id_table;
|
|
|
|
char num_ports;
|
|
|
|
|
|
|
|
struct list_head driver_list;
|
|
|
|
struct device_driver driver;
|
2006-12-18 03:50:23 +07:00
|
|
|
struct usb_driver *usb_driver;
|
|
|
|
struct usb_dynids dynids;
|
2009-05-12 03:24:07 +07:00
|
|
|
int max_in_flight_urbs;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
int (*probe)(struct usb_serial *serial, const struct usb_device_id *id);
|
|
|
|
int (*attach)(struct usb_serial *serial);
|
2005-04-17 05:20:36 +07:00
|
|
|
int (*calc_num_ports) (struct usb_serial *serial);
|
|
|
|
|
2009-06-02 22:53:55 +07:00
|
|
|
void (*disconnect)(struct usb_serial *serial);
|
|
|
|
void (*release)(struct usb_serial *serial);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
int (*port_probe)(struct usb_serial_port *port);
|
|
|
|
int (*port_remove)(struct usb_serial_port *port);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
int (*suspend)(struct usb_serial *serial, pm_message_t message);
|
|
|
|
int (*resume)(struct usb_serial *serial);
|
2007-04-28 01:54:57 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* serial function calls */
|
2008-07-22 17:09:07 +07:00
|
|
|
/* Called by console with tty = NULL and by tty */
|
|
|
|
int (*open)(struct tty_struct *tty,
|
|
|
|
struct usb_serial_port *port, struct file *filp);
|
2009-06-11 18:26:29 +07:00
|
|
|
void (*close)(struct usb_serial_port *port);
|
2008-07-22 17:09:07 +07:00
|
|
|
int (*write)(struct tty_struct *tty, struct usb_serial_port *port,
|
|
|
|
const unsigned char *buf, int count);
|
|
|
|
/* Called only by the tty layer */
|
|
|
|
int (*write_room)(struct tty_struct *tty);
|
|
|
|
int (*ioctl)(struct tty_struct *tty, struct file *file,
|
2008-01-31 06:21:33 +07:00
|
|
|
unsigned int cmd, unsigned long arg);
|
2008-07-22 17:09:07 +07:00
|
|
|
void (*set_termios)(struct tty_struct *tty,
|
|
|
|
struct usb_serial_port *port, struct ktermios *old);
|
|
|
|
void (*break_ctl)(struct tty_struct *tty, int break_state);
|
|
|
|
int (*chars_in_buffer)(struct tty_struct *tty);
|
|
|
|
void (*throttle)(struct tty_struct *tty);
|
|
|
|
void (*unthrottle)(struct tty_struct *tty);
|
|
|
|
int (*tiocmget)(struct tty_struct *tty, struct file *file);
|
|
|
|
int (*tiocmset)(struct tty_struct *tty, struct file *file,
|
2008-01-31 06:21:33 +07:00
|
|
|
unsigned int set, unsigned int clear);
|
2009-06-11 18:26:29 +07:00
|
|
|
/* Called by the tty layer for port level work. There may or may not
|
|
|
|
be an attached tty at this point */
|
|
|
|
void (*dtr_rts)(struct usb_serial_port *port, int on);
|
|
|
|
int (*carrier_raised)(struct usb_serial_port *port);
|
2008-07-22 17:09:07 +07:00
|
|
|
/* USB events */
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
|
|
|
void (*read_int_callback)(struct urb *urb);
|
|
|
|
void (*write_int_callback)(struct urb *urb);
|
|
|
|
void (*read_bulk_callback)(struct urb *urb);
|
|
|
|
void (*write_bulk_callback)(struct urb *urb);
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
2008-01-31 06:21:33 +07:00
|
|
|
#define to_usb_serial_driver(d) \
|
|
|
|
container_of(d, struct usb_serial_driver, driver)
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2005-06-21 11:15:16 +07:00
|
|
|
extern int usb_serial_register(struct usb_serial_driver *driver);
|
|
|
|
extern void usb_serial_deregister(struct usb_serial_driver *driver);
|
2006-05-23 11:58:49 +07:00
|
|
|
extern void usb_serial_port_softint(struct usb_serial_port *port);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
extern int usb_serial_probe(struct usb_interface *iface,
|
|
|
|
const struct usb_device_id *id);
|
2005-04-17 05:20:36 +07:00
|
|
|
extern void usb_serial_disconnect(struct usb_interface *iface);
|
|
|
|
|
2007-04-28 01:54:57 +07:00
|
|
|
extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
|
|
|
|
extern int usb_serial_resume(struct usb_interface *intf);
|
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
extern int ezusb_writememory(struct usb_serial *serial, int address,
|
|
|
|
unsigned char *data, int length, __u8 bRequest);
|
|
|
|
extern int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* USB Serial console functions */
|
|
|
|
#ifdef CONFIG_USB_SERIAL_CONSOLE
|
2008-01-31 06:21:33 +07:00
|
|
|
extern void usb_serial_console_init(int debug, int minor);
|
|
|
|
extern void usb_serial_console_exit(void);
|
2006-04-25 12:46:17 +07:00
|
|
|
extern void usb_serial_console_disconnect(struct usb_serial *serial);
|
2005-04-17 05:20:36 +07:00
|
|
|
#else
|
2008-01-31 06:21:33 +07:00
|
|
|
static inline void usb_serial_console_init(int debug, int minor) { }
|
|
|
|
static inline void usb_serial_console_exit(void) { }
|
2006-04-25 12:46:17 +07:00
|
|
|
static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Functions needed by other parts of the usbserial core */
|
2008-01-31 06:21:33 +07:00
|
|
|
extern struct usb_serial *usb_serial_get_by_index(unsigned int minor);
|
2006-04-25 12:46:17 +07:00
|
|
|
extern void usb_serial_put(struct usb_serial *serial);
|
2008-07-22 17:09:07 +07:00
|
|
|
extern int usb_serial_generic_open(struct tty_struct *tty,
|
|
|
|
struct usb_serial_port *port, struct file *filp);
|
|
|
|
extern int usb_serial_generic_write(struct tty_struct *tty,
|
|
|
|
struct usb_serial_port *port, const unsigned char *buf, int count);
|
2009-06-11 18:26:29 +07:00
|
|
|
extern void usb_serial_generic_close(struct usb_serial_port *port);
|
2008-01-31 06:21:33 +07:00
|
|
|
extern int usb_serial_generic_resume(struct usb_serial *serial);
|
2008-07-22 17:09:07 +07:00
|
|
|
extern int usb_serial_generic_write_room(struct tty_struct *tty);
|
|
|
|
extern int usb_serial_generic_chars_in_buffer(struct tty_struct *tty);
|
2008-01-31 06:21:33 +07:00
|
|
|
extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
|
|
|
|
extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
|
2008-07-22 17:09:07 +07:00
|
|
|
extern void usb_serial_generic_throttle(struct tty_struct *tty);
|
|
|
|
extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
|
2009-06-02 22:53:55 +07:00
|
|
|
extern void usb_serial_generic_disconnect(struct usb_serial *serial);
|
|
|
|
extern void usb_serial_generic_release(struct usb_serial *serial);
|
2008-01-31 06:21:33 +07:00
|
|
|
extern int usb_serial_generic_register(int debug);
|
|
|
|
extern void usb_serial_generic_deregister(void);
|
2009-05-12 03:24:09 +07:00
|
|
|
extern void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port,
|
|
|
|
gfp_t mem_flags);
|
|
|
|
extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port,
|
|
|
|
unsigned int ch);
|
|
|
|
extern int usb_serial_handle_break(struct usb_serial_port *port);
|
|
|
|
|
2008-01-31 06:21:33 +07:00
|
|
|
|
|
|
|
extern int usb_serial_bus_register(struct usb_serial_driver *device);
|
|
|
|
extern void usb_serial_bus_deregister(struct usb_serial_driver *device);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2005-06-21 11:15:16 +07:00
|
|
|
extern struct usb_serial_driver usb_serial_generic_device;
|
2005-04-17 05:20:36 +07:00
|
|
|
extern struct bus_type usb_serial_bus_type;
|
|
|
|
extern struct tty_driver *usb_serial_tty_driver;
|
|
|
|
|
|
|
|
static inline void usb_serial_debug_data(int debug,
|
|
|
|
struct device *dev,
|
|
|
|
const char *function, int size,
|
|
|
|
const unsigned char *data)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (debug) {
|
2008-01-31 06:21:33 +07:00
|
|
|
dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ",
|
|
|
|
function, size);
|
2005-04-17 05:20:36 +07:00
|
|
|
for (i = 0; i < size; ++i)
|
2008-01-31 06:21:33 +07:00
|
|
|
printk("%.2x ", data[i]);
|
|
|
|
printk("\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use our own dbg macro */
|
|
|
|
#undef dbg
|
2008-01-31 06:21:33 +07:00
|
|
|
#define dbg(format, arg...) \
|
|
|
|
do { \
|
|
|
|
if (debug) \
|
|
|
|
printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , \
|
|
|
|
## arg); \
|
|
|
|
} while (0)
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-08 01:45:32 +07:00
|
|
|
#endif /* __LINUX_USB_SERIAL_H */
|
2005-04-17 05:20:36 +07:00
|
|
|
|