Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

This commit is contained in:
Linus Torvalds 2005-09-08 17:21:02 -07:00
commit 5420520973
80 changed files with 7407 additions and 4077 deletions

View file

@ -0,0 +1,203 @@
Driver documentation for yealink usb-p1k phones
0. Status
~~~~~~~~~
The p1k is a relatively cheap usb 1.1 phone with:
- keyboard full support, yealink.ko / input event API
- LCD full support, yealink.ko / sysfs API
- LED full support, yealink.ko / sysfs API
- dialtone full support, yealink.ko / sysfs API
- ringtone full support, yealink.ko / sysfs API
- audio playback full support, snd_usb_audio.ko / alsa API
- audio record full support, snd_usb_audio.ko / alsa API
For vendor documentation see http://www.yealink.com
1. Compilation (stand alone version)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Currently only kernel 2.6.x.y versions are supported.
In order to build the yealink.ko module do:
make
If you encounter problems please check if in the MAKE_OPTS variable in
the Makefile is pointing to the location where your kernel sources
are located, default /usr/src/linux.
2. keyboard features
~~~~~~~~~~~~~~~~~~~~
The current mapping in the kernel is provided by the map_p1k_to_key
function:
Physical USB-P1K button layout input events
up up
IN OUT left, right
down down
pickup C hangup enter, backspace, escape
1 2 3 1, 2, 3
4 5 6 4, 5, 6,
7 8 9 7, 8, 9,
* 0 # *, 0, #,
The "up" and "down" keys, are symbolised by arrows on the button.
The "pickup" and "hangup" keys are symbolised by a green and red phone
on the button.
3. LCD features
~~~~~~~~~~~~~~~
The LCD is divided and organised as a 3 line display:
|[] [][] [][] [][] in |[][]
|[] M [][] D [][] : [][] out |[][]
store
NEW REP SU MO TU WE TH FR SA
[] [] [] [] [] [] [] [] [] [] [] []
[] [] [] [] [] [] [] [] [] [] [] []
Line 1 Format (see below) : 18.e8.M8.88...188
Icon names : M D : IN OUT STORE
Line 2 Format : .........
Icon name : NEW REP SU MO TU WE TH FR SA
Line 3 Format : 888888888888
Format description:
From a user space perspective the world is seperated in "digits" and "icons".
A digit can have a character set, an icon can only be ON or OFF.
Format specifier
'8' : Generic 7 segment digit with individual addressable segments
Reduced capabillity 7 segm digit, when segments are hard wired together.
'1' : 2 segments digit only able to produce a 1.
'e' : Most significant day of the month digit,
able to produce at least 1 2 3.
'M' : Most significant minute digit,
able to produce at least 0 1 2 3 4 5.
Icons or pictograms:
'.' : For example like AM, PM, SU, a 'dot' .. or other single segment
elements.
4. Driver usage
~~~~~~~~~~~~~~~
For userland the following interfaces are available using the sysfs interface:
/sys/.../
line1 Read/Write, lcd line1
line2 Read/Write, lcd line2
line3 Read/Write, lcd line3
get_icons Read, returns a set of available icons.
hide_icon Write, hide the element by writing the icon name.
show_icon Write, display the element by writing the icon name.
map_seg7 Read/Write, the 7 segments char set, common for all
yealink phones. (see map_to_7segment.h)
ringtone Write, upload binary representation of a ringtone,
see yealink.c. status EXPERIMENTAL due to potential
races between async. and sync usb calls.
4.1 lineX
~~~~~~~~~
Reading /sys/../lineX will return the format string with its current value:
Example:
cat ./line3
888888888888
Linux Rocks!
Writing to /sys/../lineX will set the coresponding LCD line.
- Excess characters are ignored.
- If less characters are written than allowed, the remaining digits are
unchanged.
- The tab '\t'and '\n' char does not overwrite the original content.
- Writing a space to an icon will always hide its content.
Example:
date +"%m.%e.%k:%M" | sed 's/^0/ /' > ./line1
Will update the LCD with the current date & time.
4.2 get_icons
~~~~~~~~~~~~~
Reading will return all available icon names and its current settings:
cat ./get_icons
on M
on D
on :
IN
OUT
STORE
NEW
REP
SU
MO
TU
WE
TH
FR
SA
LED
DIALTONE
RINGTONE
4.3 show/hide icons
~~~~~~~~~~~~~~~~~~~
Writing to these files will update the state of the icon.
Only one icon at a time can be updated.
If an icon is also on a ./lineX the corresponding value is
updated with the first letter of the icon.
Example - light up the store icon:
echo -n "STORE" > ./show_icon
cat ./line1
18.e8.M8.88...188
S
Example - sound the ringtone for 10 seconds:
echo -n RINGTONE > /sys/..../show_icon
sleep 10
echo -n RINGTONE > /sys/..../hide_icon
5. Sound features
~~~~~~~~~~~~~~~~~
Sound is supported by the ALSA driver: snd_usb_audio
One 16-bit channel with sample and playback rates of 8000 Hz is the practical
limit of the device.
Example - recording test:
arecord -v -d 10 -r 8000 -f S16_LE -t wav foobar.wav
Example - playback test:
aplay foobar.wav
6. Credits & Acknowledgments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Olivier Vandorpe, for starting the usbb2k-api project doing much of
the reverse engineering.
- Martin Diehl, for pointing out how to handle USB memory allocation.
- Dmitry Torokhov, for the numerous code reviews and suggestions.

View file

@ -116,6 +116,12 @@ M: ajk@iehk.rwth-aachen.de
L: linux-hams@vger.kernel.org
S: Maintained
YEALINK PHONE DRIVER
P: Henk Vergonet
M: Henk.Vergonet@gmail.com
L: usbb2k-api-dev@nongnu.org
S: Maintained
8139CP 10/100 FAST ETHERNET DRIVER
P: Jeff Garzik
M: jgarzik@pobox.com

View file

@ -16,9 +16,10 @@
* -- verify the 13 conditions and do bulk resets
* -- kill last_pipe and simply do two-state clearing on both pipes
* -- verify protocol (bulk) from USB descriptors (maybe...)
* -- highmem and sg
* -- highmem
* -- move top_sense and work_bcs into separate allocations (if they survive)
* for cache purists and esoteric architectures.
* -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ?
* -- prune comments, they are too volumnous
* -- Exterminate P3 printks
* -- Resove XXX's
@ -171,7 +172,7 @@ struct bulk_cs_wrap {
*/
struct ub_dev;
#define UB_MAX_REQ_SG 1
#define UB_MAX_REQ_SG 4
#define UB_MAX_SECTORS 64
/*
@ -234,13 +235,10 @@ struct ub_scsi_cmd {
int stat_count; /* Retries getting status. */
/*
* We do not support transfers from highmem pages
* because the underlying USB framework does not do what we need.
*/
char *data; /* Requested buffer */
unsigned int len; /* Requested length */
// struct scatterlist sgv[UB_MAX_REQ_SG];
unsigned int current_sg;
unsigned int nsg; /* sgv[nsg] */
struct scatterlist sgv[UB_MAX_REQ_SG];
struct ub_lun *lun;
void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
@ -389,17 +387,18 @@ struct ub_dev {
struct bulk_cs_wrap work_bcs;
struct usb_ctrlrequest work_cr;
int sg_stat[UB_MAX_REQ_SG+1];
struct ub_scsi_trace tr;
};
/*
*/
static void ub_cleanup(struct ub_dev *sc);
static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq);
static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);
static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct request *rq);
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
struct request *rq);
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct request *rq);
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_end_rq(struct request *rq, int uptodate);
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@ -407,6 +406,7 @@ static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
static void ub_scsi_action(unsigned long _dev);
static void ub_scsi_dispatch(struct ub_dev *sc);
static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc);
static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@ -500,7 +500,8 @@ static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
}
}
static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr, char *page)
static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
char *page)
{
struct usb_interface *intf;
struct ub_dev *sc;
@ -523,6 +524,13 @@ static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr, c
cnt += sprintf(page + cnt,
"qlen %d qmax %d\n",
sc->cmd_queue.qlen, sc->cmd_queue.qmax);
cnt += sprintf(page + cnt,
"sg %d %d %d %d %d\n",
sc->sg_stat[0],
sc->sg_stat[1],
sc->sg_stat[2],
sc->sg_stat[3],
sc->sg_stat[4]);
list_for_each (p, &sc->luns) {
lun = list_entry(p, struct ub_lun, link);
@ -744,20 +752,20 @@ static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
* The request function is our main entry point
*/
static void ub_bd_rq_fn(request_queue_t *q)
static void ub_request_fn(request_queue_t *q)
{
struct ub_lun *lun = q->queuedata;
struct request *rq;
while ((rq = elv_next_request(q)) != NULL) {
if (ub_bd_rq_fn_1(lun, rq) != 0) {
if (ub_request_fn_1(lun, rq) != 0) {
blk_stop_queue(q);
break;
}
}
}
static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
{
struct ub_dev *sc = lun->udev;
struct ub_scsi_cmd *cmd;
@ -774,9 +782,8 @@ static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
blkdev_dequeue_request(rq);
if (blk_pc_request(rq)) {
rc = ub_cmd_build_packet(sc, cmd, rq);
rc = ub_cmd_build_packet(sc, lun, cmd, rq);
} else {
rc = ub_cmd_build_block(sc, lun, cmd, rq);
}
@ -791,7 +798,7 @@ static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
cmd->back = rq;
cmd->tag = sc->tagcnt++;
if ((rc = ub_submit_scsi(sc, cmd)) != 0) {
if (ub_submit_scsi(sc, cmd) != 0) {
ub_put_cmd(lun, cmd);
ub_end_rq(rq, 0);
return 0;
@ -804,58 +811,31 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct request *rq)
{
int ub_dir;
#if 0 /* We use rq->buffer for now */
struct scatterlist *sg;
int n_elem;
#endif
unsigned int block, nblks;
if (rq_data_dir(rq) == WRITE)
ub_dir = UB_DIR_WRITE;
else
ub_dir = UB_DIR_READ;
cmd->dir = ub_dir;
/*
* get scatterlist from block layer
*/
#if 0 /* We use rq->buffer for now */
sg = &cmd->sgv[0];
n_elem = blk_rq_map_sg(q, rq, sg);
n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]);
if (n_elem <= 0) {
ub_put_cmd(lun, cmd);
ub_end_rq(rq, 0);
blk_start_queue(q);
return 0; /* request with no s/g entries? */
printk(KERN_INFO "%s: failed request map (%d)\n",
sc->name, n_elem); /* P3 */
return -1; /* request with no s/g entries? */
}
if (n_elem != 1) { /* Paranoia */
if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */
printk(KERN_WARNING "%s: request with %d segments\n",
sc->name, n_elem);
ub_put_cmd(lun, cmd);
ub_end_rq(rq, 0);
blk_start_queue(q);
return 0;
}
#endif
/*
* XXX Unfortunately, this check does not work. It is quite possible
* to get bogus non-null rq->buffer if you allow sg by mistake.
*/
if (rq->buffer == NULL) {
/*
* This must not happen if we set the queue right.
* The block level must create bounce buffers for us.
*/
static int do_print = 1;
if (do_print) {
printk(KERN_WARNING "%s: unmapped block request"
" flags 0x%lx sectors %lu\n",
sc->name, rq->flags, rq->nr_sectors);
do_print = 0;
}
return -1;
}
cmd->nsg = n_elem;
sc->sg_stat[n_elem]++;
/*
* build the command
@ -876,30 +856,15 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
cmd->cdb[8] = nblks;
cmd->cdb_len = 10;
cmd->dir = ub_dir;
cmd->data = rq->buffer;
cmd->len = rq->nr_sectors * 512;
return 0;
}
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
struct request *rq)
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct request *rq)
{
if (rq->data_len != 0 && rq->data == NULL) {
static int do_print = 1;
if (do_print) {
printk(KERN_WARNING "%s: unmapped packet request"
" flags 0x%lx length %d\n",
sc->name, rq->flags, rq->data_len);
do_print = 0;
}
return -1;
}
memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
cmd->cdb_len = rq->cmd_len;
int n_elem;
if (rq->data_len == 0) {
cmd->dir = UB_DIR_NONE;
@ -908,8 +873,29 @@ static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
cmd->dir = UB_DIR_WRITE;
else
cmd->dir = UB_DIR_READ;
}
cmd->data = rq->data;
/*
* get scatterlist from block layer
*/
n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]);
if (n_elem < 0) {
printk(KERN_INFO "%s: failed request map (%d)\n",
sc->name, n_elem); /* P3 */
return -1;
}
if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */
printk(KERN_WARNING "%s: request with %d segments\n",
sc->name, n_elem);
return -1;
}
cmd->nsg = n_elem;
sc->sg_stat[n_elem]++;
memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
cmd->cdb_len = rq->cmd_len;
cmd->len = rq->data_len;
return 0;
@ -919,24 +905,34 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
{
struct request *rq = cmd->back;
struct ub_lun *lun = cmd->lun;
struct gendisk *disk = lun->disk;
request_queue_t *q = disk->queue;
int uptodate;
if (blk_pc_request(rq)) {
/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
rq->sense_len = UB_SENSE_SIZE;
}
if (cmd->error == 0)
if (cmd->error == 0) {
uptodate = 1;
else
if (blk_pc_request(rq)) {
if (cmd->act_len >= rq->data_len)
rq->data_len = 0;
else
rq->data_len -= cmd->act_len;
}
} else {
uptodate = 0;
if (blk_pc_request(rq)) {
/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
rq->sense_len = UB_SENSE_SIZE;
if (sc->top_sense[0] != 0)
rq->errors = SAM_STAT_CHECK_CONDITION;
else
rq->errors = DID_ERROR << 16;
}
}
ub_put_cmd(lun, cmd);
ub_end_rq(rq, uptodate);
blk_start_queue(q);
blk_start_queue(lun->disk->queue);
}
static void ub_end_rq(struct request *rq, int uptodate)
@ -1014,7 +1010,7 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->last_pipe = sc->send_bulk_pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.transfer_flags = 0;
/* Fill what we shouldn't be filling, because usb-storage did so. */
sc->work_urb.actual_length = 0;
@ -1103,7 +1099,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
{
struct urb *urb = &sc->work_urb;
struct bulk_cs_wrap *bcs;
int pipe;
int rc;
if (atomic_read(&sc->poison)) {
@ -1204,38 +1199,13 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
goto Bad_End;
}
if (cmd->dir == UB_DIR_NONE) {
if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {
ub_state_stat(sc, cmd);
return;
}
UB_INIT_COMPLETION(sc->work_done);
if (cmd->dir == UB_DIR_READ)
pipe = sc->recv_bulk_pipe;
else
pipe = sc->send_bulk_pipe;
sc->last_pipe = pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
cmd->data, cmd->len, ub_urb_complete, sc);
sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
ub_complete(&sc->work_done);
ub_state_done(sc, cmd, rc);
return;
}
sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
add_timer(&sc->work_timer);
cmd->state = UB_CMDST_DATA;
ub_cmdtr_state(sc, cmd);
// udelay(125); // usb-storage has this
ub_data_start(sc, cmd);
} else if (cmd->state == UB_CMDST_DATA) {
if (urb->status == -EPIPE) {
@ -1257,16 +1227,22 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
if (urb->status == -EOVERFLOW) {
/*
* A babble? Failure, but we must transfer CSW now.
* XXX This is going to end in perpetual babble. Reset.
*/
cmd->error = -EOVERFLOW; /* A cheap trick... */
} else {
if (urb->status != 0)
goto Bad_End;
ub_state_stat(sc, cmd);
return;
}
if (urb->status != 0)
goto Bad_End;
cmd->act_len = urb->actual_length;
cmd->act_len += urb->actual_length;
ub_cmdtr_act_len(sc, cmd);
if (++cmd->current_sg < cmd->nsg) {
ub_data_start(sc, cmd);
return;
}
ub_state_stat(sc, cmd);
} else if (cmd->state == UB_CMDST_STAT) {
@ -1399,6 +1375,46 @@ Bad_End: /* Little Excel is dead */
ub_state_done(sc, cmd, -EIO);
}
/*
* Factorization helper for the command state machine:
* Initiate a data segment transfer.
*/
static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
{
struct scatterlist *sg = &cmd->sgv[cmd->current_sg];
int pipe;
int rc;
UB_INIT_COMPLETION(sc->work_done);
if (cmd->dir == UB_DIR_READ)
pipe = sc->recv_bulk_pipe;
else
pipe = sc->send_bulk_pipe;
sc->last_pipe = pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
page_address(sg->page) + sg->offset, sg->length,
ub_urb_complete, sc);
sc->work_urb.transfer_flags = 0;
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
ub_complete(&sc->work_done);
ub_state_done(sc, cmd, rc);
return;
}
sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
add_timer(&sc->work_timer);
cmd->state = UB_CMDST_DATA;
ub_cmdtr_state(sc, cmd);
}
/*
* Factorization helper for the command state machine:
* Finish the command.
@ -1426,7 +1442,7 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->last_pipe = sc->recv_bulk_pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
&sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.transfer_flags = 0;
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
@ -1484,6 +1500,7 @@ static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
{
struct ub_scsi_cmd *scmd;
struct scatterlist *sg;
int rc;
if (cmd->cdb[0] == REQUEST_SENSE) {
@ -1492,12 +1509,17 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
}
scmd = &sc->top_rqs_cmd;
memset(scmd, 0, sizeof(struct ub_scsi_cmd));
scmd->cdb[0] = REQUEST_SENSE;
scmd->cdb[4] = UB_SENSE_SIZE;
scmd->cdb_len = 6;
scmd->dir = UB_DIR_READ;
scmd->state = UB_CMDST_INIT;
scmd->data = sc->top_sense;
scmd->nsg = 1;
sg = &scmd->sgv[0];
sg->page = virt_to_page(sc->top_sense);
sg->offset = (unsigned int)sc->top_sense & (PAGE_SIZE-1);
sg->length = UB_SENSE_SIZE;
scmd->len = UB_SENSE_SIZE;
scmd->lun = cmd->lun;
scmd->done = ub_top_sense_done;
@ -1541,7 +1563,7 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
(unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.transfer_flags = 0;
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
@ -1560,7 +1582,7 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
*/
static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
{
unsigned char *sense = scmd->data;
unsigned char *sense = sc->top_sense;
struct ub_scsi_cmd *cmd;
/*
@ -1852,6 +1874,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
struct ub_capacity *ret)
{
struct ub_scsi_cmd *cmd;
struct scatterlist *sg;
char *p;
enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
unsigned long flags;
@ -1872,7 +1895,11 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
cmd->cdb_len = 10;
cmd->dir = UB_DIR_READ;
cmd->state = UB_CMDST_INIT;
cmd->data = p;
cmd->nsg = 1;
sg = &cmd->sgv[0];
sg->page = virt_to_page(p);
sg->offset = (unsigned int)p & (PAGE_SIZE-1);
sg->length = 8;
cmd->len = 8;
cmd->lun = lun;
cmd->done = ub_probe_done;
@ -2289,7 +2316,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
disk->driverfs_dev = &sc->intf->dev; /* XXX Many to one ok? */
rc = -ENOMEM;
if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL)
if ((q = blk_init_queue(ub_request_fn, &sc->lock)) == NULL)
goto err_blkqinit;
disk->queue = q;

View file

@ -267,7 +267,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
frame, IRDA_USB_SPEED_MTU,
speed_bulk_callback, self);
urb->transfer_buffer_length = USB_IRDA_HEADER;
urb->transfer_flags = URB_ASYNC_UNLINK;
urb->transfer_flags = 0;
/* Irq disabled -> GFP_ATOMIC */
if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) {
@ -401,15 +401,12 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
skb->data, IRDA_SKB_MAX_MTU,
write_bulk_callback, skb);
urb->transfer_buffer_length = skb->len;
/* Note : unlink *must* be Asynchronous because of the code in
* irda_usb_net_timeout() -> call in irq - Jean II */
urb->transfer_flags = URB_ASYNC_UNLINK;
/* This flag (URB_ZERO_PACKET) indicates that what we send is not
* a continuous stream of data but separate packets.
* In this case, the USB layer will insert an empty USB frame (TD)
* after each of our packets that is exact multiple of the frame size.
* This is how the dongle will detect the end of packet - Jean II */
urb->transfer_flags |= URB_ZERO_PACKET;
urb->transfer_flags = URB_ZERO_PACKET;
/* Generate min turn time. FIXME: can we do better than this? */
/* Trying to a turnaround time at this level is trying to measure
@ -630,8 +627,6 @@ static void irda_usb_net_timeout(struct net_device *netdev)
* in completion handler, because urb->status will
* be -ENOENT. We will fix that at the next watchdog,
* leaving more time to USB to recover...
* Also, we are in interrupt, so we need to have
* URB_ASYNC_UNLINK to work properly...
* Jean II */
done = 1;
break;
@ -1008,9 +1003,7 @@ static int irda_usb_net_close(struct net_device *netdev)
}
}
/* Cancel Tx and speed URB - need to be synchronous to avoid races */
self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
usb_kill_urb(self->tx_urb);
self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
usb_kill_urb(self->speed_urb);
/* Stop and remove instance of IrLAP */
@ -1521,9 +1514,7 @@ static void irda_usb_disconnect(struct usb_interface *intf)
usb_kill_urb(self->rx_urb[i]);
/* Cancel Tx and speed URB.
* Toggle flags to make sure it's synchronous. */
self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
usb_kill_urb(self->tx_urb);
self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
usb_kill_urb(self->speed_urb);
}

View file

@ -715,13 +715,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
instance->rcv_buf, PAGE_SIZE,
cxacru_blocking_completion, &instance->rcv_done, 1);
instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_fill_int_urb(instance->snd_urb,
usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD),
instance->snd_buf, PAGE_SIZE,
cxacru_blocking_completion, &instance->snd_done, 4);
instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK;
init_MUTEX(&instance->cm_serialize);

View file

@ -4,9 +4,22 @@
comment "USB Device Class drivers"
depends on USB
config OBSOLETE_OSS_USB_DRIVER
bool "Obsolete OSS USB drivers"
depends on USB && SOUND
help
This option enables support for the obsolete USB Audio and Midi
drivers that are scheduled for removal in the near future since
there are ALSA drivers for the same hardware.
Please contact Adrian Bunk <bunk@stusta.de> if you had to
say Y here because of missing support in the ALSA drivers.
If unsure, say N.
config USB_AUDIO
tristate "USB Audio support"
depends on USB && SOUND
depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
help
Say Y here if you want to connect USB audio equipment such as
speakers to your computer's USB port. You only need this if you use
@ -40,10 +53,12 @@ config USB_BLUETOOTH_TTY
config USB_MIDI
tristate "USB MIDI support"
depends on USB && SOUND
depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
---help---
Say Y here if you want to connect a USB MIDI device to your
computer's USB port. This driver is for devices that comply with
computer's USB port. You only need this if you use the OSS
sound system; USB MIDI devices are supported by ALSA's USB
audio driver. This driver is for devices that comply with
'Universal Serial Bus Device Class Definition for MIDI Device'.
The following devices are known to work:

View file

@ -310,8 +310,9 @@ static int usblp_check_status(struct usblp *usblp, int err)
error = usblp_read_status (usblp, usblp->statusbuf);
if (error < 0) {
err("usblp%d: error %d reading printer status",
usblp->minor, error);
if (printk_ratelimit())
err("usblp%d: error %d reading printer status",
usblp->minor, error);
return 0;
}
@ -604,7 +605,9 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case LPGETSTATUS:
if (usblp_read_status(usblp, usblp->statusbuf)) {
err("usblp%d: failed reading printer status", usblp->minor);
if (printk_ratelimit())
err("usblp%d: failed reading printer status",
usblp->minor);
retval = -EIO;
goto done;
}

View file

@ -3,14 +3,14 @@
#
usbcore-objs := usb.o hub.o hcd.o urb.o message.o \
config.o file.o buffer.o sysfs.o
config.o file.o buffer.o sysfs.o devio.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
endif
ifeq ($(CONFIG_USB_DEVICEFS),y)
usbcore-objs += devio.o inode.o devices.o
usbcore-objs += inode.o devices.o
endif
obj-$(CONFIG_USB) += usbcore.o

View file

@ -43,6 +43,7 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
@ -50,6 +51,10 @@
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
#define USB_MAXBUS 64
#define USB_DEVICE_MAX USB_MAXBUS * 128
static struct class *usb_device_class;
struct async {
struct list_head asynclist;
struct dev_state *ps;
@ -71,6 +76,8 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
dev_info( dev , format , ## arg); \
} while (0)
#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
#define MAX_USBFS_BUFFER_SIZE 16384
@ -487,7 +494,7 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
*/
static int usbdev_open(struct inode *inode, struct file *file)
{
struct usb_device *dev;
struct usb_device *dev = NULL;
struct dev_state *ps;
int ret;
@ -501,11 +508,16 @@ static int usbdev_open(struct inode *inode, struct file *file)
lock_kernel();
ret = -ENOENT;
dev = usb_get_dev(inode->u.generic_ip);
/* check if we are called from a real node or usbfs */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_minor(iminor(inode));
if (!dev)
dev = inode->u.generic_ip;
if (!dev) {
kfree(ps);
goto out;
}
usb_get_dev(dev);
ret = 0;
ps->dev = dev;
ps->file = file;
@ -1226,7 +1238,6 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
int retval = 0;
struct usb_interface *intf = NULL;
struct usb_driver *driver = NULL;
int i;
/* get input parameters and alloc buffer */
if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
@ -1258,15 +1269,6 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
/* disconnect kernel driver from interface */
case USBDEVFS_DISCONNECT:
/* don't allow the user to unbind the hub driver from
* a hub with children to manage */
for (i = 0; i < ps->dev->maxchild; ++i) {
if (ps->dev->children[i])
retval = -EBUSY;
}
if (retval)
break;
down_write(&usb_bus_type.subsys.rwsem);
if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver);
@ -1477,3 +1479,79 @@ struct file_operations usbfs_device_file_operations = {
.open = usbdev_open,
.release = usbdev_release,
};
struct usb_device *usbdev_lookup_minor(int minor)
{
struct class_device *class_dev;
struct usb_device *dev = NULL;
down(&usb_device_class->sem);
list_for_each_entry(class_dev, &usb_device_class->children, node) {
if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
dev = class_dev->class_data;
break;
}
}
up(&usb_device_class->sem);
return dev;
};
void usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
dev->class_dev = class_device_create(usb_device_class,
MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
dev->class_dev->class_data = dev;
}
void usbdev_remove(struct usb_device *dev)
{
class_device_unregister(dev->class_dev);
}
static struct cdev usb_device_cdev = {
.kobj = {.name = "usb_device", },
.owner = THIS_MODULE,
};
int __init usbdev_init(void)
{
int retval;
retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
"usb_device");
if (retval) {
err("unable to register minors for usb_device");
goto out;
}
cdev_init(&usb_device_cdev, &usbfs_device_file_operations);
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
if (retval) {
err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
goto out;
}
usb_device_class = class_create(THIS_MODULE, "usb_device");
if (IS_ERR(usb_device_class)) {
err("unable to register usb_device class");
retval = PTR_ERR(usb_device_class);
usb_device_class = NULL;
cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
}
out:
return retval;
}
void usbdev_cleanup(void)
{
class_destroy(usb_device_class);
cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
}

View file

@ -339,11 +339,11 @@ extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
* to preallocate bandwidth)
*/
#define USB2_HOST_DELAY 5 /* nsec, guess */
#define HS_NSECS(bytes) ( ((55 * 8 * 2083)/1000) \
+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
#define HS_NSECS(bytes) ( ((55 * 8 * 2083) \
+ (2083UL * (3 + BitTime(bytes))))/1000 \
+ USB2_HOST_DELAY)
#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083)/1000) \
+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083) \
+ (2083UL * (3 + BitTime(bytes))))/1000 \
+ USB2_HOST_DELAY)
#define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
#define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes))

View file

@ -492,6 +492,23 @@ static int hub_hub_status(struct usb_hub *hub,
return ret;
}
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
{
struct usb_device *hdev = hub->hdev;
int ret;
if (hdev->children[port1-1] && set_state) {
usb_set_device_state(hdev->children[port1-1],
USB_STATE_NOTATTACHED);
}
ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
if (ret)
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
port1, ret);
return ret;
}
static int hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint)
{
@ -610,19 +627,33 @@ static int hub_configure(struct usb_hub *hub,
break;
}
/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
case 0x00:
if (hdev->descriptor.bDeviceProtocol != 0)
dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n");
case HUB_TTTT_8_BITS:
if (hdev->descriptor.bDeviceProtocol != 0) {
hub->tt.think_time = 666;
dev_dbg(hub_dev, "TT requires at most %d "
"FS bit times (%d ns)\n",
8, hub->tt.think_time);
}
break;
case 0x20:
dev_dbg(hub_dev, "TT requires at most 16 FS bit times\n");
case HUB_TTTT_16_BITS:
hub->tt.think_time = 666 * 2;
dev_dbg(hub_dev, "TT requires at most %d "
"FS bit times (%d ns)\n",
16, hub->tt.think_time);
break;
case 0x40:
dev_dbg(hub_dev, "TT requires at most 24 FS bit times\n");
case HUB_TTTT_24_BITS:
hub->tt.think_time = 666 * 3;
dev_dbg(hub_dev, "TT requires at most %d "
"FS bit times (%d ns)\n",
24, hub->tt.think_time);
break;
case 0x60:
dev_dbg(hub_dev, "TT requires at most 32 FS bit times\n");
case HUB_TTTT_32_BITS:
hub->tt.think_time = 666 * 4;
dev_dbg(hub_dev, "TT requires at most %d "
"FS bit times (%d ns)\n",
32, hub->tt.think_time);
break;
}
@ -712,20 +743,36 @@ fail:
static unsigned highspeed_hubs;
/* Called after the hub driver is unbound from a hub with children */
static void hub_remove_children_work(void *__hub)
{
struct usb_hub *hub = __hub;
struct usb_device *hdev = hub->hdev;
int i;
kfree(hub);
usb_lock_device(hdev);
for (i = 0; i < hdev->maxchild; ++i) {
if (hdev->children[i])
usb_disconnect(&hdev->children[i]);
}
usb_unlock_device(hdev);
usb_put_dev(hdev);
}
static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev;
int n, port1;
if (!hub)
return;
usb_set_intfdata (intf, NULL);
hdev = hub->hdev;
if (hdev->speed == USB_SPEED_HIGH)
highspeed_hubs--;
usb_set_intfdata (intf, NULL);
hub_quiesce(hub);
usb_free_urb(hub->urb);
hub->urb = NULL;
@ -746,8 +793,27 @@ static void hub_disconnect(struct usb_interface *intf)
hub->buffer = NULL;
}
/* Free the memory */
kfree(hub);
/* If there are any children then this is an unbind only, not a
* physical disconnection. The active ports must be disabled
* and later on we must call usb_disconnect(). We can't call
* it now because we may not hold the hub's device lock.
*/
n = 0;
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
if (hdev->children[port1 - 1]) {
++n;
hub_port_disable(hub, port1, 1);
}
}
if (n == 0)
kfree(hub);
else {
/* Reuse the hub->leds work_struct for our own purposes */
INIT_WORK(&hub->leds, hub_remove_children_work, hub);
schedule_work(&hub->leds);
usb_get_dev(hdev);
}
}
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
@ -1051,6 +1117,7 @@ void usb_disconnect(struct usb_device **pdev)
dev_dbg (&udev->dev, "unregistering device\n");
release_address(udev);
usbfs_remove_device(udev);
usbdev_remove(udev);
usb_remove_sysfs_dev_files(udev);
/* Avoid races with recursively_mark_NOTATTACHED() */
@ -1290,6 +1357,7 @@ int usb_new_device(struct usb_device *udev)
/* USB device state == configured ... usable */
/* add a /proc/bus/usb entry */
usbdev_add(udev);
usbfs_add_device(udev);
return 0;
@ -1428,23 +1496,6 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
return status;
}
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
{
struct usb_device *hdev = hub->hdev;
int ret;
if (hdev->children[port1-1] && set_state) {
usb_set_device_state(hdev->children[port1-1],
USB_STATE_NOTATTACHED);
}
ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
if (ret)
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
port1, ret);
return ret;
}
/*
* Disable a port and mark a logical connnect-change event, so that some
* time later khubd will disconnect() any existing usb_device on the port

View file

@ -157,6 +157,12 @@ enum hub_led_mode {
struct usb_device;
/* Transaction Translator Think Times, in bits */
#define HUB_TTTT_8_BITS 0x00
#define HUB_TTTT_16_BITS 0x20
#define HUB_TTTT_24_BITS 0x40
#define HUB_TTTT_32_BITS 0x60
/*
* As of USB 2.0, full/low speed devices are segregated into trees.
* One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
@ -170,6 +176,7 @@ struct usb_device;
struct usb_tt {
struct usb_device *hub; /* upstream highspeed hub */
int multi; /* true means one TT per port */
unsigned think_time; /* think time in ns */
/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
spinlock_t lock;

View file

@ -728,16 +728,10 @@ int __init usbfs_init(void)
{
int retval;
retval = usb_register(&usbfs_driver);
retval = register_filesystem(&usb_fs_type);
if (retval)
return retval;
retval = register_filesystem(&usb_fs_type);
if (retval) {
usb_deregister(&usbfs_driver);
return retval;
}
/* create mount point for usbfs */
usbdir = proc_mkdir("usb", proc_bus);
@ -746,7 +740,6 @@ int __init usbfs_init(void)
void usbfs_cleanup(void)
{
usb_deregister(&usbfs_driver);
unregister_filesystem(&usb_fs_type);
if (usbdir)
remove_proc_entry("usb", proc_bus);

View file

@ -48,7 +48,6 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
init_completion(&done);
urb->context = &done;
urb->transfer_flags |= URB_ASYNC_UNLINK;
urb->actual_length = 0;
status = usb_submit_urb(urb, GFP_NOIO);
@ -266,7 +265,9 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs)
continue;
if (found) {
status = usb_unlink_urb (io->urbs [i]);
if (status != -EINPROGRESS && status != -EBUSY)
if (status != -EINPROGRESS
&& status != -ENODEV
&& status != -EBUSY)
dev_err (&io->dev->dev,
"%s, unlink --> %d\n",
__FUNCTION__, status);
@ -357,8 +358,7 @@ int usb_sg_init (
if (!io->urbs)
goto nomem;
urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP
| URB_NO_INTERRUPT;
urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
if (usb_pipein (pipe))
urb_flags |= URB_SHORT_NOT_OK;

View file

@ -309,9 +309,8 @@ int usb_submit_urb(struct urb *urb, unsigned mem_flags)
unsigned int allowed;
/* enforce simple/standard policy */
allowed = URB_ASYNC_UNLINK; // affects later unlinks
allowed |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
allowed |= URB_NO_INTERRUPT;
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
URB_NO_INTERRUPT);
switch (temp) {
case PIPE_BULK:
if (is_out)
@ -400,14 +399,8 @@ int usb_submit_urb(struct urb *urb, unsigned mem_flags)
* canceled (rather than any other code) and will quickly be removed
* from host controller data structures.
*
* In the past, clearing the URB_ASYNC_UNLINK transfer flag for the
* URB indicated that the request was synchronous. This usage is now
* deprecated; if the flag is clear the call will be forwarded to
* usb_kill_urb() and the return value will be 0. In the future, drivers
* should call usb_kill_urb() directly for synchronous unlinking.
*
* When the URB_ASYNC_UNLINK transfer flag for the URB is set, this
* request is asynchronous. Success is indicated by returning -EINPROGRESS,
* This request is always asynchronous.
* Success is indicated by returning -EINPROGRESS,
* at which time the URB will normally have been unlinked but not yet
* given back to the device driver. When it is called, the completion
* function will see urb->status == -ECONNRESET. Failure is indicated
@ -453,17 +446,6 @@ int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
#ifdef CONFIG_DEBUG_KERNEL
if (printk_ratelimit()) {
printk(KERN_NOTICE "usb_unlink_urb() is deprecated for "
"synchronous unlinks. Use usb_kill_urb() instead.\n");
WARN_ON(1);
}
#endif
usb_kill_urb(urb);
return 0;
}
if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
return -ENODEV;
return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET);

View file

@ -65,6 +65,16 @@ static int generic_probe (struct device *dev)
}
static int generic_remove (struct device *dev)
{
struct usb_device *udev = to_usb_device(dev);
/* if this is only an unbind, not a physical disconnect, then
* unconfigure the device */
if (udev->state == USB_STATE_CONFIGURED)
usb_set_configuration(udev, 0);
/* in case the call failed or the device was suspended */
if (udev->state >= USB_STATE_CONFIGURED)
usb_disable_device(udev, 0);
return 0;
}
@ -912,7 +922,7 @@ int usb_trylock_device(struct usb_device *udev)
* is neither BINDING nor BOUND. Rather than sleeping to wait for the
* lock, the routine polls repeatedly. This is to prevent deadlock with
* disconnect; in some drivers (such as usb-storage) the disconnect()
* callback will block waiting for a device reset to complete.
* or suspend() method will block waiting for a device reset to complete.
*
* Returns a negative error code for failure, otherwise 1 or 0 to indicate
* that the device will or will not have to be unlocked. (0 can be
@ -922,6 +932,8 @@ int usb_trylock_device(struct usb_device *udev)
int usb_lock_device_for_reset(struct usb_device *udev,
struct usb_interface *iface)
{
unsigned long jiffies_expire = jiffies + HZ;
if (udev->state == USB_STATE_NOTATTACHED)
return -ENODEV;
if (udev->state == USB_STATE_SUSPENDED)
@ -938,6 +950,12 @@ int usb_lock_device_for_reset(struct usb_device *udev,
}
while (!usb_trylock_device(udev)) {
/* If we can't acquire the lock after waiting one second,
* we're probably deadlocked */
if (time_after(jiffies, jiffies_expire))
return -EBUSY;
msleep(15);
if (udev->state == USB_STATE_NOTATTACHED)
return -ENODEV;
@ -1478,13 +1496,18 @@ static int __init usb_init(void)
retval = usb_major_init();
if (retval)
goto major_init_failed;
retval = usb_register(&usbfs_driver);
if (retval)
goto driver_register_failed;
retval = usbdev_init();
if (retval)
goto usbdevice_init_failed;
retval = usbfs_init();
if (retval)
goto fs_init_failed;
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
retval = driver_register(&usb_generic_driver);
if (!retval)
goto out;
@ -1493,7 +1516,11 @@ static int __init usb_init(void)
hub_init_failed:
usbfs_cleanup();
fs_init_failed:
usb_major_cleanup();
usbdev_cleanup();
usbdevice_init_failed:
usb_deregister(&usbfs_driver);
driver_register_failed:
usb_major_cleanup();
major_init_failed:
usb_host_cleanup();
host_init_failed:
@ -1514,6 +1541,8 @@ static void __exit usb_exit(void)
driver_unregister(&usb_generic_driver);
usb_major_cleanup();
usbfs_cleanup();
usb_deregister(&usbfs_driver);
usbdev_cleanup();
usb_hub_cleanup();
usb_host_cleanup();
bus_unregister(&usb_bus_type);

View file

@ -37,6 +37,11 @@ extern struct file_operations usbfs_devices_fops;
extern struct file_operations usbfs_device_file_operations;
extern void usbfs_conn_disc_event(void);
extern int usbdev_init(void);
extern void usbdev_cleanup(void);
extern void usbdev_add(struct usb_device *dev);
extern void usbdev_remove(struct usb_device *dev);
extern struct usb_device *usbdev_lookup_minor(int minor);
struct dev_state {
struct list_head list; /* state list */

View file

@ -2181,6 +2181,7 @@ eth_bind (struct usb_gadget *gadget)
u8 cdc = 1, zlp = 1, rndis = 1;
struct usb_ep *in_ep, *out_ep, *status_ep = NULL;
int status = -ENOMEM;
int gcnum;
/* these flags are only ever cleared; compiler take note */
#ifndef DEV_CONFIG_CDC
@ -2194,44 +2195,26 @@ eth_bind (struct usb_gadget *gadget)
* standard protocol is _strongly_ preferred for interop purposes.
* (By everyone except Microsoft.)
*/
if (gadget_is_net2280 (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
} else if (gadget_is_dummy (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0202);
} else if (gadget_is_pxa (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203);
if (gadget_is_pxa (gadget)) {
/* pxa doesn't support altsettings */
cdc = 0;
} else if (gadget_is_sh(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);
/* sh doesn't support multiple interfaces or configs */
cdc = 0;
rndis = 0;
} else if (gadget_is_sa1100 (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);
/* hardware can't write zlps */
zlp = 0;
/* sa1100 CAN do CDC, without status endpoint ... we use
* non-CDC to be compatible with ARM Linux-2.4 "usb-eth".
*/
cdc = 0;
} else if (gadget_is_goku (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206);
} else if (gadget_is_mq11xx (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
} else if (gadget_is_omap (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
} else if (gadget_is_n9604(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
} else if (gadget_is_pxa27x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
} else if (gadget_is_s3c2410(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
} else if (gadget_is_at91(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213);
} else {
}
gcnum = usb_gadget_controller_number (gadget);
if (gcnum >= 0)
device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
else {
/* can't assume CDC works. don't want to default to
* anything less functional on CDC-capable hardware,
* so we fail in this case.

View file

@ -3713,6 +3713,7 @@ static void fsg_unbind(struct usb_gadget *gadget)
static int __init check_parameters(struct fsg_dev *fsg)
{
int prot;
int gcnum;
/* Store the default values */
mod_data.transport_type = USB_PR_BULK;
@ -3724,33 +3725,13 @@ static int __init check_parameters(struct fsg_dev *fsg)
mod_data.can_stall = 0;
if (mod_data.release == 0xffff) { // Parameter wasn't set
if (gadget_is_net2280(fsg->gadget))
mod_data.release = 0x0301;
else if (gadget_is_dummy(fsg->gadget))
mod_data.release = 0x0302;
else if (gadget_is_pxa(fsg->gadget))
mod_data.release = 0x0303;
else if (gadget_is_sh(fsg->gadget))
mod_data.release = 0x0304;
/* The sa1100 controller is not supported */
else if (gadget_is_goku(fsg->gadget))
mod_data.release = 0x0306;
else if (gadget_is_mq11xx(fsg->gadget))
mod_data.release = 0x0307;
else if (gadget_is_omap(fsg->gadget))
mod_data.release = 0x0308;
else if (gadget_is_lh7a40x(fsg->gadget))
mod_data.release = 0x0309;
else if (gadget_is_n9604(fsg->gadget))
mod_data.release = 0x0310;
else if (gadget_is_pxa27x(fsg->gadget))
mod_data.release = 0x0311;
else if (gadget_is_s3c2410(gadget))
mod_data.release = 0x0312;
else if (gadget_is_at91(fsg->gadget))
mod_data.release = 0x0313;
if (gadget_is_sa1100(fsg->gadget))
gcnum = -1;
else
gcnum = usb_gadget_controller_number(fsg->gadget);
if (gcnum >= 0)
mod_data.release = 0x0300 + gcnum;
else {
WARN(fsg, "controller '%s' not recognized\n",
fsg->gadget->name);

View file

@ -5,6 +5,7 @@
*
* This could eventually work like the ARM mach_is_*() stuff, driven by
* some config file that gets updated as new hardware is supported.
* (And avoiding the runtime comparisons in typical one-choice cases.)
*
* NOTE: some of these controller drivers may not be available yet.
*/
@ -86,7 +87,61 @@
#define gadget_is_at91(g) 0
#endif
#ifdef CONFIG_USB_GADGET_IMX
#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name)
#else
#define gadget_is_imx(g) 0
#endif
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
// ...
/**
* usb_gadget_controller_number - support bcdDevice id convention
* @gadget: the controller being driven
*
* Return a 2-digit BCD value associated with the peripheral controller,
* suitable for use as part of a bcdDevice value, or a negative error code.
*
* NOTE: this convention is purely optional, and has no meaning in terms of
* any USB specification. If you want to use a different convention in your
* gadget driver firmware -- maybe a more formal revision ID -- feel free.
*
* Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
* to change their behavior accordingly. For example it might help avoiding
* some chip bug.
*/
static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
{
if (gadget_is_net2280(gadget))
return 0x01;
else if (gadget_is_dummy(gadget))
return 0x02;
else if (gadget_is_pxa(gadget))
return 0x03;
else if (gadget_is_sh(gadget))
return 0x04;
else if (gadget_is_sa1100(gadget))
return 0x05;
else if (gadget_is_goku(gadget))
return 0x06;
else if (gadget_is_mq11xx(gadget))
return 0x07;
else if (gadget_is_omap(gadget))
return 0x08;
else if (gadget_is_lh7a40x(gadget))
return 0x09;
else if (gadget_is_n9604(gadget))
return 0x10;
else if (gadget_is_pxa27x(gadget))
return 0x11;
else if (gadget_is_s3c2410(gadget))
return 0x12;
else if (gadget_is_at91(gadget))
return 0x13;
else if (gadget_is_imx(gadget))
return 0x14;
return -ENOENT;
}

View file

@ -1422,49 +1422,20 @@ static int gs_bind(struct usb_gadget *gadget)
int ret;
struct usb_ep *ep;
struct gs_dev *dev;
int gcnum;
/* device specific */
if (gadget_is_net2280(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0001);
} else if (gadget_is_pxa(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0002);
} else if (gadget_is_sh(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0003);
/* sh doesn't support multiple interfaces or configs */
/* Some controllers can't support CDC ACM:
* - sh doesn't support multiple interfaces or configs;
* - sa1100 doesn't have a third interrupt endpoint
*/
if (gadget_is_sh(gadget) || gadget_is_sa1100(gadget))
use_acm = 0;
} else if (gadget_is_sa1100(gadget)) {
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0004);
/* sa1100 doesn't support necessary endpoints */
use_acm = 0;
} else if (gadget_is_goku(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0005);
} else if (gadget_is_mq11xx(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0006);
} else if (gadget_is_omap(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0007);
} else if (gadget_is_lh7a40x(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0008);
} else if (gadget_is_n9604(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0009);
} else if (gadget_is_pxa27x(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0011);
} else if (gadget_is_s3c2410(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0012);
} else if (gadget_is_at91(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0013);
} else {
cpu_to_le16(GS_VERSION_NUM | gcnum);
else {
printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
gadget->name);
/* unrecognized, but safe unless bulk is REALLY quirky */

View file

@ -1139,6 +1139,13 @@ zero_bind (struct usb_gadget *gadget)
{
struct zero_dev *dev;
struct usb_ep *ep;
int gcnum;
/* FIXME this can't yet work right with SH ... it has only
* one configuration, numbered one.
*/
if (gadget_is_sh(gadget))
return -ENODEV;
/* Bulk-only drivers like this one SHOULD be able to
* autoconfigure on any sane usb controller driver,
@ -1161,43 +1168,10 @@ autoconf_fail:
EP_OUT_NAME = ep->name;
ep->driver_data = ep; /* claim */
/*
* DRIVER POLICY CHOICE: you may want to do this differently.
* One thing to avoid is reusing a bcdDevice revision code
* with different host-visible configurations or behavior
* restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
*/
if (gadget_is_net2280 (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
} else if (gadget_is_pxa (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203);
#if 0
} else if (gadget_is_sh(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);
/* SH has only one configuration; see "loopdefault" */
device_desc.bNumConfigurations = 1;
/* FIXME make 1 == default.bConfigurationValue */
#endif
} else if (gadget_is_sa1100 (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);
} else if (gadget_is_goku (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206);
} else if (gadget_is_mq11xx (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
} else if (gadget_is_omap (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
} else if (gadget_is_n9604(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
} else if (gadget_is_pxa27x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
} else if (gadget_is_s3c2410(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
} else if (gadget_is_at91(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213);
} else {
gcnum = usb_gadget_controller_number (gadget);
if (gcnum >= 0)
device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
* so warn about unrcognized controllers, don't panic.

View file

@ -677,6 +677,9 @@ qh_make (
goto done;
}
} else {
struct usb_tt *tt = urb->dev->tt;
int think_time;
/* gap is f(FS/LS transfer times) */
qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
is_input, 0, maxp) / (125 * 1000);
@ -690,6 +693,10 @@ qh_make (
qh->c_usecs = HS_USECS (0);
}
think_time = tt ? tt->think_time : 0;
qh->tt_usecs = NS_TO_US (think_time +
usb_calc_bus_time (urb->dev->speed,
is_input, 0, max_packet (maxp)));
qh->period = urb->interval;
}
}

View file

@ -700,6 +700,7 @@ iso_stream_init (
} else {
u32 addr;
int think_time;
addr = dev->ttport << 24;
if (!ehci_is_TDI(ehci)
@ -709,6 +710,9 @@ iso_stream_init (
addr |= epnum << 8;
addr |= dev->devnum;
stream->usecs = HS_USECS_ISO (maxp);
think_time = dev->tt ? dev->tt->think_time : 0;
stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
dev->speed, is_input, 1, maxp));
if (is_input) {
u32 tmp;

View file

@ -421,6 +421,7 @@ struct ehci_qh {
u8 usecs; /* intr bandwidth */
u8 gap_uf; /* uframes split/csplit gap */
u8 c_usecs; /* ... split completion bw */
u16 tt_usecs; /* tt downstream bandwidth */
unsigned short period; /* polling interval */
unsigned short start; /* where polling starts */
#define NO_FRAME ((unsigned short)~0) /* pick new start */
@ -479,6 +480,7 @@ struct ehci_iso_stream {
*/
u8 interval;
u8 usecs, c_usecs;
u16 tt_usecs;
u16 maxp;
u16 raw_mask;
unsigned bandwidth;

View file

@ -83,7 +83,7 @@
#include "../core/hcd.h"
#include "isp116x.h"
#define DRIVER_VERSION "08 Apr 2005"
#define DRIVER_VERSION "05 Aug 2005"
#define DRIVER_DESC "ISP116x USB Host Controller Driver"
MODULE_DESCRIPTION(DRIVER_DESC);
@ -629,14 +629,12 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
ERR("Unrecoverable error\n");
/* What should we do here? Reset? */
}
if (intstat & HCINT_RHSC) {
isp116x->rhstatus =
isp116x_read_reg32(isp116x, HCRHSTATUS);
isp116x->rhport[0] =
isp116x_read_reg32(isp116x, HCRHPORT1);
isp116x->rhport[1] =
isp116x_read_reg32(isp116x, HCRHPORT2);
}
if (intstat & HCINT_RHSC)
/* When root hub or any of its ports is going
to come out of suspend, it may take more
than 10ms for status bits to stabilize. */
mod_timer(&hcd->rh_timer, jiffies
+ msecs_to_jiffies(20) + 1);
if (intstat & HCINT_RD) {
DBG("---- remote wakeup\n");
schedule_work(&isp116x->rh_resume);
@ -925,20 +923,27 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
int ports, i, changed = 0;
unsigned long flags;
if (!HC_IS_RUNNING(hcd->state))
return -ESHUTDOWN;
ports = isp116x->rhdesca & RH_A_NDP;
/* Report no status change now, if we are scheduled to be
called later */
if (timer_pending(&hcd->rh_timer))
return 0;
/* init status */
ports = isp116x->rhdesca & RH_A_NDP;
spin_lock_irqsave(&isp116x->lock, flags);
isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))
buf[0] = changed = 1;
else
buf[0] = 0;
for (i = 0; i < ports; i++) {
u32 status = isp116x->rhport[i];
u32 status = isp116x->rhport[i] =
isp116x_read_reg32(isp116x, i ? HCRHPORT2 : HCRHPORT1);
if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
| RH_PS_OCIC | RH_PS_PRSC)) {
@ -947,6 +952,7 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
continue;
}
}
spin_unlock_irqrestore(&isp116x->lock, flags);
return changed;
}
@ -1463,10 +1469,6 @@ static int isp116x_sw_reset(struct isp116x *isp116x)
return ret;
}
/*
Reset. Tries to perform platform-specific hardware
reset first; falls back to software reset.
*/
static int isp116x_reset(struct usb_hcd *hcd)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
@ -1474,17 +1476,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
u16 clkrdy = 0;
int ret = 0, timeout = 15 /* ms */ ;
if (isp116x->board && isp116x->board->reset) {
/* Hardware reset */
isp116x->board->reset(hcd->self.controller, 1);
msleep(10);
if (isp116x->board->clock)
isp116x->board->clock(hcd->self.controller, 1);
msleep(1);
isp116x->board->reset(hcd->self.controller, 0);
} else
ret = isp116x_sw_reset(isp116x);
ret = isp116x_sw_reset(isp116x);
if (ret)
return ret;
@ -1501,10 +1493,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
ERR("Clock not ready after 20ms\n");
/* After sw_reset the clock won't report to be ready, if
H_WAKEUP pin is high. */
if (!isp116x->board || !isp116x->board->reset)
ERR("The driver does not support hardware wakeup.\n");
ERR("Please make sure that the H_WAKEUP pin "
"is pulled low!\n");
ERR("Please make sure that the H_WAKEUP pin is pulled low!\n");
ret = -ENODEV;
}
return ret;
@ -1527,15 +1516,7 @@ static void isp116x_stop(struct usb_hcd *hcd)
isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
spin_unlock_irqrestore(&isp116x->lock, flags);
/* Put the chip into reset state */
if (isp116x->board && isp116x->board->reset)
isp116x->board->reset(hcd->self.controller, 0);
else
isp116x_sw_reset(isp116x);
/* Stop the clock */
if (isp116x->board && isp116x->board->clock)
isp116x->board->clock(hcd->self.controller, 0);
isp116x_sw_reset(isp116x);
}
/*
@ -1561,6 +1542,9 @@ static int isp116x_start(struct usb_hcd *hcd)
return -ENODEV;
}
/* To be removed in future */
hcd->uses_new_polling = 1;
isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
@ -1569,7 +1553,7 @@ static int isp116x_start(struct usb_hcd *hcd)
if (board->sel15Kres)
val |= HCHWCFG_15KRSEL;
/* Remote wakeup won't work without working clock */
if (board->clknotstop || board->remote_wakeup_enable)
if (board->remote_wakeup_enable)
val |= HCHWCFG_CLKNOTSTOP;
if (board->oc_enable)
val |= HCHWCFG_ANALOG_OC;
@ -1580,16 +1564,13 @@ static int isp116x_start(struct usb_hcd *hcd)
isp116x_write_reg16(isp116x, HCHWCFG, val);
/* ----- Root hub conf */
val = 0;
/* AN10003_1.pdf recommends NPS to be always 1 */
if (board->no_power_switching)
val |= RH_A_NPS;
if (board->power_switching_mode)
val |= RH_A_PSM;
if (board->potpg)
val |= (board->potpg << 24) & RH_A_POTPGT;
else
val |= (25 << 24) & RH_A_POTPGT;
val = (25 << 24) & RH_A_POTPGT;
/* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
be always set. Yet, instead, we request individual port
power switching. */
val |= RH_A_PSM;
/* Report overcurrent per port */
val |= RH_A_OCPM;
isp116x_write_reg32(isp116x, HCRHDESCA, val);
isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
@ -1619,9 +1600,6 @@ static int isp116x_start(struct usb_hcd *hcd)
/* Go operational */
val = HCCONTROL_USB_OPER;
/* Remote wakeup connected - NOT SUPPORTED */
/* if (board->remote_wakeup_connected)
val |= HCCONTROL_RWC; */
if (board->remote_wakeup_enable)
val |= HCCONTROL_RWE;
isp116x_write_reg32(isp116x, HCCONTROL, val);
@ -1670,7 +1648,7 @@ static int __init_or_module isp116x_remove(struct device *dev)
struct platform_device *pdev;
struct resource *res;
if(!hcd)
if (!hcd)
return 0;
isp116x = hcd_to_isp116x(hcd);
pdev = container_of(dev, struct platform_device, dev);

View file

@ -14,8 +14,6 @@
* This file is licenced under the GPL.
*/
#include <asm/usb.h>
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@ -23,9 +21,7 @@
* usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
* Context: !in_interrupt()
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
* Allocates basic resources for this USB host controller.
*
* Store this function in the HCD's struct pci_driver as probe().
*/
@ -37,7 +33,6 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
struct ohci_hcd *ohci;
struct resource *res;
int irq;
struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
pr_debug("initializing PPC-SOC USB Controller\n");
@ -73,9 +68,6 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
goto err2;
}
if (pd->start && (retval = pd->start(pdev)))
goto err3;
ohci = hcd_to_ohci(hcd);
ohci->flags |= OHCI_BIG_ENDIAN;
ohci_hcd_init(ohci);
@ -85,9 +77,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
return retval;
pr_debug("Removing PPC-SOC USB Controller\n");
if (pd && pd->stop)
pd->stop(pdev);
err3:
iounmap(hcd->regs);
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
@ -105,25 +95,21 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
* @pdev: USB Host Controller being removed
* Context: !in_interrupt()
*
* Reverses the effect of usb_hcd_ppc_soc_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* Reverses the effect of usb_hcd_ppc_soc_probe().
* It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
*
*/
static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd,
struct platform_device *pdev)
{
struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
usb_remove_hcd(hcd);
pr_debug("stopping PPC-SOC USB Controller\n");
if (pd && pd->stop)
pd->stop(pdev);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_hcd_put(hcd);
usb_put_hcd(hcd);
}
static int __devinit

View file

@ -129,7 +129,7 @@ static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info,
if (info->power_control != NULL) {
info->port[port-1].power = to;
(info->power_control)(port, to);
(info->power_control)(port-1, to);
}
}
@ -339,8 +339,8 @@ int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
struct usb_hcd *hcd = NULL;
int retval;
s3c2410_usb_set_power(dev->dev.platform_data, 0, 1);
s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
if (hcd == NULL)

View file

@ -230,6 +230,20 @@ config USB_EGALAX
To compile this driver as a module, choose M here: the
module will be called touchkitusb.
config USB_YEALINK
tristate "Yealink usb-p1k voip phone"
depends on USB && INPUT && EXPERIMENTAL
---help---
Say Y here if you want to enable keyboard and LCD functions of the
Yealink usb-p1k usb phones. The audio part is enabled by the generic
usb sound driver, so you might want to enable that as well.
For information about how to use these additional functions, see
<file:Documentation/input/yealink.txt>.
To compile this driver as a module, choose M here: the module will be
called yealink.
config USB_XPAD
tristate "X-Box gamepad support"
depends on USB && INPUT

View file

@ -39,4 +39,5 @@ obj-$(CONFIG_USB_EGALAX) += touchkitusb.o
obj-$(CONFIG_USB_POWERMATE) += powermate.o
obj-$(CONFIG_USB_WACOM) += wacom.o
obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o

View file

@ -1444,6 +1444,8 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_NETWORKANALYSER 0x2020
#define USB_DEVICE_ID_POWERCONTROL 0x2030
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_BLUETOOTH 0x1000
/*
* Alphabetically sorted blacklist by quirk type.
@ -1462,6 +1464,7 @@ static struct hid_blacklist {
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_BLUETOOTH, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
@ -1685,7 +1688,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0,
hid_irq_in, hid, interval);
hid->urbin->transfer_dma = hid->inbuf_dma;
hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
} else {
if (hid->urbout)
continue;
@ -1695,7 +1698,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0,
hid_irq_out, hid, interval);
hid->urbout->transfer_dma = hid->outbuf_dma;
hid->urbout->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
}
}
@ -1747,7 +1750,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
hid->ctrlbuf, 1, hid_ctrl, hid);
hid->urbctrl->setup_dma = hid->cr_dma;
hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_ASYNC_UNLINK);
hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
return hid;

View file

@ -431,11 +431,6 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
/* See if the offered device matches what we can accept */
if ((udev->descriptor.idVendor != USB_KEYSPAN_VENDOR_ID) ||
(udev->descriptor.idProduct != USB_KEYSPAN_PRODUCT_UIA11) )
return -ENODEV;
/* allocate memory for our device state and initialize it */
remote = kmalloc(sizeof(*remote), GFP_KERNEL);
if (remote == NULL) {

View file

@ -0,0 +1,189 @@
/*
* drivers/usb/input/map_to_7segment.h
*
* Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.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 the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MAP_TO_7SEGMENT_H
#define MAP_TO_7SEGMENT_H
/* This file provides translation primitives and tables for the conversion
* of (ASCII) characters to a 7-segments notation.
*
* The 7 segment's wikipedia notation below is used as standard.
* See: http://en.wikipedia.org/wiki/Seven_segment_display
*
* Notation: +-a-+
* f b
* +-g-+
* e c
* +-d-+
*
* Usage:
*
* Register a map variable, and fill it with a character set:
* static SEG7_DEFAULT_MAP(map_seg7);
*
*
* Then use for conversion:
* seg7 = map_to_seg7(&map_seg7, some_char);
* ...
*
* In device drivers it is recommended, if required, to make the char map
* accessible via the sysfs interface using the following scheme:
*
* static ssize_t show_map(struct device *dev, char *buf) {
* memcpy(buf, &map_seg7, sizeof(map_seg7));
* return sizeof(map_seg7);
* }
* static ssize_t store_map(struct device *dev, const char *buf, size_t cnt) {
* if(cnt != sizeof(map_seg7))
* return -EINVAL;
* memcpy(&map_seg7, buf, cnt);
* return cnt;
* }
* static DEVICE_ATTR(map_seg7, PERMS_RW, show_map, store_map);
*
* History:
* 2005-05-31 RFC linux-kernel@vger.kernel.org
*/
#include <linux/errno.h>
#define BIT_SEG7_A 0
#define BIT_SEG7_B 1
#define BIT_SEG7_C 2
#define BIT_SEG7_D 3
#define BIT_SEG7_E 4
#define BIT_SEG7_F 5
#define BIT_SEG7_G 6
#define BIT_SEG7_RESERVED 7
struct seg7_conversion_map {
unsigned char table[128];
};
static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
{
return c & 0x7f ? map->table[c] : -EINVAL;
}
#define SEG7_CONVERSION_MAP(_name, _map) \
struct seg7_conversion_map _name = { .table = { _map } }
/*
* It is recommended to use a facility that allows user space to redefine
* custom character sets for LCD devices. Please use a sysfs interface
* as described above.
*/
#define MAP_TO_SEG7_SYSFS_FILE "map_seg7"
/*******************************************************************************
* ASCII conversion table
******************************************************************************/
#define _SEG7(l,a,b,c,d,e,f,g) \
( a<<BIT_SEG7_A | b<<BIT_SEG7_B | c<<BIT_SEG7_C | d<<BIT_SEG7_D | \
e<<BIT_SEG7_E | f<<BIT_SEG7_F | g<<BIT_SEG7_G )
#define _MAP_0_32_ASCII_SEG7_NON_PRINTABLE \
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
#define _MAP_33_47_ASCII_SEG7_SYMBOL \
_SEG7('!',0,0,0,0,1,1,0), _SEG7('"',0,1,0,0,0,1,0), _SEG7('#',0,1,1,0,1,1,0),\
_SEG7('$',1,0,1,1,0,1,1), _SEG7('%',0,0,1,0,0,1,0), _SEG7('&',1,0,1,1,1,1,1),\
_SEG7('\'',0,0,0,0,0,1,0),_SEG7('(',1,0,0,1,1,1,0), _SEG7(')',1,1,1,1,0,0,0),\
_SEG7('*',0,1,1,0,1,1,1), _SEG7('+',0,1,1,0,0,0,1), _SEG7(',',0,0,0,0,1,0,0),\
_SEG7('-',0,0,0,0,0,0,1), _SEG7('.',0,0,0,0,1,0,0), _SEG7('/',0,1,0,0,1,0,1),
#define _MAP_48_57_ASCII_SEG7_NUMERIC \
_SEG7('0',1,1,1,1,1,1,0), _SEG7('1',0,1,1,0,0,0,0), _SEG7('2',1,1,0,1,1,0,1),\
_SEG7('3',1,1,1,1,0,0,1), _SEG7('4',0,1,1,0,0,1,1), _SEG7('5',1,0,1,1,0,1,1),\
_SEG7('6',1,0,1,1,1,1,1), _SEG7('7',1,1,1,0,0,0,0), _SEG7('8',1,1,1,1,1,1,1),\
_SEG7('9',1,1,1,1,0,1,1),
#define _MAP_58_64_ASCII_SEG7_SYMBOL \
_SEG7(':',0,0,0,1,0,0,1), _SEG7(';',0,0,0,1,0,0,1), _SEG7('<',1,0,0,0,0,1,1),\
_SEG7('=',0,0,0,1,0,0,1), _SEG7('>',1,1,0,0,0,0,1), _SEG7('?',1,1,1,0,0,1,0),\
_SEG7('@',1,1,0,1,1,1,1),
#define _MAP_65_90_ASCII_SEG7_ALPHA_UPPR \
_SEG7('A',1,1,1,0,1,1,1), _SEG7('B',1,1,1,1,1,1,1), _SEG7('C',1,0,0,1,1,1,0),\
_SEG7('D',1,1,1,1,1,1,0), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
_SEG7('G',1,1,1,1,0,1,1), _SEG7('H',0,1,1,0,1,1,1), _SEG7('I',0,1,1,0,0,0,0),\
_SEG7('J',0,1,1,1,0,0,0), _SEG7('K',0,1,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
_SEG7('M',1,1,1,0,1,1,0), _SEG7('N',1,1,1,0,1,1,0), _SEG7('O',1,1,1,1,1,1,0),\
_SEG7('P',1,1,0,0,1,1,1), _SEG7('Q',1,1,1,1,1,1,0), _SEG7('R',1,1,1,0,1,1,1),\
_SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('U',0,1,1,1,1,1,0),\
_SEG7('V',0,1,1,1,1,1,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
_SEG7('Y',0,1,1,0,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
#define _MAP_91_96_ASCII_SEG7_SYMBOL \
_SEG7('[',1,0,0,1,1,1,0), _SEG7('\\',0,0,1,0,0,1,1),_SEG7(']',1,1,1,1,0,0,0),\
_SEG7('^',1,1,0,0,0,1,0), _SEG7('_',0,0,0,1,0,0,0), _SEG7('`',0,1,0,0,0,0,0),
#define _MAP_97_122_ASCII_SEG7_ALPHA_LOWER \
_SEG7('A',1,1,1,0,1,1,1), _SEG7('b',0,0,1,1,1,1,1), _SEG7('c',0,0,0,1,1,0,1),\
_SEG7('d',0,1,1,1,1,0,1), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
_SEG7('G',1,1,1,1,0,1,1), _SEG7('h',0,0,1,0,1,1,1), _SEG7('i',0,0,1,0,0,0,0),\
_SEG7('j',0,0,1,1,0,0,0), _SEG7('k',0,0,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
_SEG7('M',1,1,1,0,1,1,0), _SEG7('n',0,0,1,0,1,0,1), _SEG7('o',0,0,1,1,1,0,1),\
_SEG7('P',1,1,0,0,1,1,1), _SEG7('q',1,1,1,0,0,1,1), _SEG7('r',0,0,0,0,1,0,1),\
_SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('u',0,0,1,1,1,0,0),\
_SEG7('v',0,0,1,1,1,0,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
_SEG7('y',0,1,1,1,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
#define _MAP_123_126_ASCII_SEG7_SYMBOL \
_SEG7('{',1,0,0,1,1,1,0), _SEG7('|',0,0,0,0,1,1,0), _SEG7('}',1,1,1,1,0,0,0),\
_SEG7('~',1,0,0,0,0,0,0),
/* Maps */
/* This set tries to map as close as possible to the visible characteristics
* of the ASCII symbol, lowercase and uppercase letters may differ in
* presentation on the display.
*/
#define MAP_ASCII7SEG_ALPHANUM \
_MAP_0_32_ASCII_SEG7_NON_PRINTABLE \
_MAP_33_47_ASCII_SEG7_SYMBOL \
_MAP_48_57_ASCII_SEG7_NUMERIC \
_MAP_58_64_ASCII_SEG7_SYMBOL \
_MAP_65_90_ASCII_SEG7_ALPHA_UPPR \
_MAP_91_96_ASCII_SEG7_SYMBOL \
_MAP_97_122_ASCII_SEG7_ALPHA_LOWER \
_MAP_123_126_ASCII_SEG7_SYMBOL
/* This set tries to map as close as possible to the symbolic characteristics
* of the ASCII character for maximum discrimination.
* For now this means all alpha chars are in lower case representations.
* (This for example facilitates the use of hex numbers with uppercase input.)
*/
#define MAP_ASCII7SEG_ALPHANUM_LC \
_MAP_0_32_ASCII_SEG7_NON_PRINTABLE \
_MAP_33_47_ASCII_SEG7_SYMBOL \
_MAP_48_57_ASCII_SEG7_NUMERIC \
_MAP_58_64_ASCII_SEG7_SYMBOL \
_MAP_97_122_ASCII_SEG7_ALPHA_LOWER \
_MAP_91_96_ASCII_SEG7_SYMBOL \
_MAP_97_122_ASCII_SEG7_ALPHA_LOWER \
_MAP_123_126_ASCII_SEG7_SYMBOL
#define SEG7_DEFAULT_MAP(_name) \
SEG7_CONVERSION_MAP(_name,MAP_ASCII7SEG_ALPHANUM)
#endif /* MAP_TO_7SEGMENT_H */

1013
drivers/usb/input/yealink.c Normal file

File diff suppressed because it is too large Load diff

220
drivers/usb/input/yealink.h Normal file
View file

@ -0,0 +1,220 @@
/*
* drivers/usb/input/yealink.h
*
* Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.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 the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INPUT_YEALINK_H
#define INPUT_YEALINK_H
/* Using the control channel on interface 3 various aspects of the phone
* can be controlled like LCD, LED, dialtone and the ringtone.
*/
struct yld_ctl_packet {
u8 cmd; /* command code, see below */
u8 size; /* 1-11, size of used data bytes. */
u16 offset; /* internal packet offset */
u8 data[11];
s8 sum; /* negative sum of 15 preceding bytes */
} __attribute__ ((packed));
#define USB_PKT_LEN sizeof(struct yld_ctl_packet)
/* The following yld_ctl_packet's are available: */
/* Init registers
*
* cmd 0x8e
* size 10
* offset 0
* data 0,0,0,0....
*/
#define CMD_INIT 0x8e
/* Request key scan
*
* cmd 0x80
* size 1
* offset 0
* data[0] on return returns the key number, if it changes there's a new
* key pressed.
*/
#define CMD_KEYPRESS 0x80
/* Request scancode
*
* cmd 0x81
* size 1
* offset key number [0-1f]
* data[0] on return returns the scancode
*/
#define CMD_SCANCODE 0x81
/* Set LCD
*
* cmd 0x04
* size 1-11
* offset 0-23
* data segment bits
*/
#define CMD_LCD 0x04
/* Set led
*
* cmd 0x05
* size 1
* offset 0
* data[0] 0 OFF / 1 ON
*/
#define CMD_LED 0x05
/* Set ringtone volume
*
* cmd 0x11
* size 1
* offset 0
* data[0] 0-0xff volume
*/
#define CMD_RING_VOLUME 0x11
/* Set ringtone notes
*
* cmd 0x02
* size 1-11
* offset 0->
* data binary representation LE16(-freq), LE16(duration) ....
*/
#define CMD_RING_NOTE 0x02
/* Sound ringtone via the speaker on the back
*
* cmd 0x03
* size 1
* offset 0
* data[0] 0 OFF / 0x24 ON
*/
#define CMD_RINGTONE 0x03
/* Sound dial tone via the ear speaker
*
* cmd 0x09
* size 1
* offset 0
* data[0] 0 OFF / 1 ON
*/
#define CMD_DIALTONE 0x09
#endif /* INPUT_YEALINK_H */
#if defined(_SEG) && defined(_PIC)
/* This table maps the LCD segments onto individual bit positions in the
* yld_status struct.
*/
/* LCD, each segment must be driven seperately.
*
* Layout:
*
* |[] [][] [][] [][] in |[][]
* |[] M [][] D [][] : [][] out |[][]
* store
*
* NEW REP SU MO TU WE TH FR SA
*
* [] [] [] [] [] [] [] [] [] [] [] []
* [] [] [] [] [] [] [] [] [] [] [] []
*/
/* Line 1
* Format : 18.e8.M8.88...188
* Icon names : M D : IN OUT STORE
*/
#define LCD_LINE1_OFFSET 0
#define LCD_LINE1_SIZE 17
/* Note: first g then f => ! ! */
/* _SEG( type a b c d e g f ) */
_SEG('1', 0,0 , 22,2 , 22,2 , 0,0 , 0,0 , 0,0 , 0,0 ),
_SEG('8', 20,1 , 20,2 , 20,4 , 20,8 , 21,4 , 21,2 , 21,1 ),
_PIC('.', 22,1 , "M" ),
_SEG('e', 18,1 , 18,2 , 18,4 , 18,1 , 19,2 , 18,1 , 19,1 ),
_SEG('8', 16,1 , 16,2 , 16,4 , 16,8 , 17,4 , 17,2 , 17,1 ),
_PIC('.', 15,8 , "D" ),
_SEG('M', 14,1 , 14,2 , 14,4 , 14,1 , 15,4 , 15,2 , 15,1 ),
_SEG('8', 12,1 , 12,2 , 12,4 , 12,8 , 13,4 , 13,2 , 13,1 ),
_PIC('.', 11,8 , ":" ),
_SEG('8', 10,1 , 10,2 , 10,4 , 10,8 , 11,4 , 11,2 , 11,1 ),
_SEG('8', 8,1 , 8,2 , 8,4 , 8,8 , 9,4 , 9,2 , 9,1 ),
_PIC('.', 7,1 , "IN" ),
_PIC('.', 7,2 , "OUT" ),
_PIC('.', 7,4 , "STORE" ),
_SEG('1', 0,0 , 5,1 , 5,1 , 0,0 , 0,0 , 0,0 , 0,0 ),
_SEG('8', 4,1 , 4,2 , 4,4 , 4,8 , 5,8 , 5,4 , 5,2 ),
_SEG('8', 2,1 , 2,2 , 2,4 , 2,8 , 3,4 , 3,2 , 3,1 ),
/* Line 2
* Format : .........
* Pict. name : NEW REP SU MO TU WE TH FR SA
*/
#define LCD_LINE2_OFFSET LCD_LINE1_OFFSET + LCD_LINE1_SIZE
#define LCD_LINE2_SIZE 9
_PIC('.', 23,2 , "NEW" ),
_PIC('.', 23,4 , "REP" ),
_PIC('.', 1,8 , "SU" ),
_PIC('.', 1,4 , "MO" ),
_PIC('.', 1,2 , "TU" ),
_PIC('.', 1,1 , "WE" ),
_PIC('.', 0,1 , "TH" ),
_PIC('.', 0,2 , "FR" ),
_PIC('.', 0,4 , "SA" ),
/* Line 3
* Format : 888888888888
*/
#define LCD_LINE3_OFFSET LCD_LINE2_OFFSET + LCD_LINE2_SIZE
#define LCD_LINE3_SIZE 12
_SEG('8', 22,16, 22,32, 22,64, 22,128, 23,128, 23,64, 23,32 ),
_SEG('8', 20,16, 20,32, 20,64, 20,128, 21,128, 21,64, 21,32 ),
_SEG('8', 18,16, 18,32, 18,64, 18,128, 19,128, 19,64, 19,32 ),
_SEG('8', 16,16, 16,32, 16,64, 16,128, 17,128, 17,64, 17,32 ),
_SEG('8', 14,16, 14,32, 14,64, 14,128, 15,128, 15,64, 15,32 ),
_SEG('8', 12,16, 12,32, 12,64, 12,128, 13,128, 13,64, 13,32 ),
_SEG('8', 10,16, 10,32, 10,64, 10,128, 11,128, 11,64, 11,32 ),
_SEG('8', 8,16, 8,32, 8,64, 8,128, 9,128, 9,64, 9,32 ),
_SEG('8', 6,16, 6,32, 6,64, 6,128, 7,128, 7,64, 7,32 ),
_SEG('8', 4,16, 4,32, 4,64, 4,128, 5,128, 5,64, 5,32 ),
_SEG('8', 2,16, 2,32, 2,64, 2,128, 3,128, 3,64, 3,32 ),
_SEG('8', 0,16, 0,32, 0,64, 0,128, 1,128, 1,64, 1,32 ),
/* Line 4
*
* The LED, DIALTONE and RINGTONE are implemented as icons and use the same
* sysfs interface.
*/
#define LCD_LINE4_OFFSET LCD_LINE3_OFFSET + LCD_LINE3_SIZE
_PIC('.', offsetof(struct yld_status, led) , 0x01, "LED" ),
_PIC('.', offsetof(struct yld_status, dialtone) , 0x01, "DIALTONE" ),
_PIC('.', offsetof(struct yld_status, ringtone) , 0x24, "RINGTONE" ),
#undef _SEG
#undef _PIC
#endif /* _SEG && _PIC */

View file

@ -426,7 +426,7 @@ static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb)
/* cancel an urb which is submitted to the chain
the result is 0 if the urb is cancelled, or -EINPROGRESS if
URB_ASYNC_UNLINK is set and the function is successfully started.
the function is successfully started.
*/
static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb)
{
@ -515,7 +515,6 @@ static void auerchain_unlink_all (pauerchain_t acp)
acep = acp->active;
if (acep) {
urbp = acep->urbp;
urbp->transfer_flags &= ~URB_ASYNC_UNLINK;
dbg ("unlink active urb");
usb_kill_urb (urbp);
}

View file

@ -464,7 +464,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size));
bytes_to_read = min(count, *actual_buffer);
if (bytes_to_read < *actual_buffer)
dev_warn(&dev->intf->dev, "Read buffer overflow, %d bytes dropped\n",
dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
*actual_buffer-bytes_to_read);
/* copy one interrupt_in_buffer from ring_buffer into userspace */
@ -528,8 +528,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
/* write the data into interrupt_out_buffer from userspace */
bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
if (bytes_to_write < count)
dev_warn(&dev->intf->dev, "Write buffer overflow, %d bytes dropped\n",count-bytes_to_write);
dbg_info(&dev->intf->dev, "%s: count = %d, bytes_to_write = %d\n", __FUNCTION__, count, bytes_to_write);
dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
retval = -EFAULT;

View file

@ -229,7 +229,7 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
sisusb_bulk_completeout, &sisusb->urbout_context[index]);
urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
urb->transfer_flags |= tflags;
urb->actual_length = 0;
if ((urb->transfer_dma = transfer_dma))
@ -295,7 +295,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
sisusb_bulk_completein, sisusb);
urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
urb->transfer_flags |= tflags;
urb->actual_length = 0;
if ((urb->transfer_dma = transfer_dma))

View file

@ -986,7 +986,6 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
u->context = &context;
u->complete = ctrl_complete;
u->transfer_flags |= URB_ASYNC_UNLINK;
}
/* queue the urbs */
@ -1052,7 +1051,6 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size);
if (!urb)
return -ENOMEM;
urb->transfer_flags |= URB_ASYNC_UNLINK;
urb->context = &completion;
urb->complete = unlink1_callback;

View file

@ -2,7 +2,7 @@
# Makefile for USB Core files and filesystem
#
usbmon-objs := mon_main.o mon_stat.o mon_text.o
usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o
# This does not use CONFIG_USB_MON because we want this to use a tristate.
obj-$(CONFIG_USB) += usbmon.o

55
drivers/usb/mon/mon_dma.c Normal file
View file

@ -0,0 +1,55 @@
/*
* The USB Monitor, inspired by Dave Harding's USBMon.
*
* mon_dma.c: Library which snoops on DMA areas.
*
* Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com)
*/
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/highmem.h>
#include <asm/page.h>
#include <linux/usb.h> /* Only needed for declarations in usb_mon.h */
#include "usb_mon.h"
#ifdef __i386__ /* CONFIG_ARCH_I386 does not exit */
#define MON_HAS_UNMAP 1
#define phys_to_page(phys) pfn_to_page((phys) >> PAGE_SHIFT)
char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
{
struct page *pg;
unsigned long flags;
unsigned char *map;
unsigned char *ptr;
/*
* On i386, a DMA handle is the "physical" address of a page.
* In other words, the bus address is equal to physical address.
* There is no IOMMU.
*/
pg = phys_to_page(dma_addr);
/*
* We are called from hardware IRQs in case of callbacks.
* But we can be called from softirq or process context in case
* of submissions. In such case, we need to protect KM_IRQ0.
*/
local_irq_save(flags);
map = kmap_atomic(pg, KM_IRQ0);
ptr = map + (dma_addr & (PAGE_SIZE-1));
memcpy(dst, ptr, len);
kunmap_atomic(map, KM_IRQ0);
local_irq_restore(flags);
return 0;
}
#endif /* __i386__ */
#ifndef MON_HAS_UNMAP
char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
{
return 'D';
}
#endif

View file

@ -91,25 +91,11 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
int len, char ev_type)
{
int pipe = urb->pipe;
unsigned char *data;
/*
* The check to see if it's safe to poke at data has an enormous
* number of corner cases, but it seems that the following is
* more or less safe.
*
* We do not even try to look transfer_buffer, because it can
* contain non-NULL garbage in case the upper level promised to
* set DMA for the HCD.
*/
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
return 'D';
if (len <= 0)
return 'L';
if ((data = urb->transfer_buffer) == NULL)
return 'Z'; /* '0' would be not as pretty. */
if (len >= DATA_MAX)
len = DATA_MAX;
/*
* Bulk is easy to shortcut reliably.
@ -126,8 +112,21 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
}
}
if (len >= DATA_MAX)
len = DATA_MAX;
/*
* The check to see if it's safe to poke at data has an enormous
* number of corner cases, but it seems that the following is
* more or less safe.
*
* We do not even try to look transfer_buffer, because it can
* contain non-NULL garbage in case the upper level promised to
* set DMA for the HCD.
*/
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
return mon_dmapeek(ep->data, urb->transfer_dma, len);
if (urb->transfer_buffer == NULL)
return 'Z'; /* '0' would be not as pretty. */
memcpy(ep->data, urb->transfer_buffer, len);
return 0;
}

View file

@ -45,6 +45,10 @@ struct mon_reader {
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
/*
*/
extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
extern struct semaphore mon_lock;
extern struct file_operations mon_fops_text;

View file

@ -99,7 +99,7 @@ config USB_USBNET
with "minidrivers" built around a common network driver core
that supports deep queues for efficient transfers. (This gives
better performance with small packets and at high speeds).
The USB host runs "usbnet", and the other end of the link might be:
- Another USB host, when using USB "network" or "data transfer"
@ -125,38 +125,63 @@ config USB_USBNET
To compile this driver as a module, choose M here: the
module will be called usbnet.
comment "USB Host-to-Host Cables"
depends on USB_USBNET
config USB_NET_AX8817X
tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters"
depends on USB_USBNET && NET_ETHERNET
select CRC32
select MII
default y
help
This option adds support for ASIX AX88xxx based USB 2.0
10/100 Ethernet adapters.
config USB_ALI_M5632
boolean "ALi M5632 based 'USB 2.0 Data Link' cables"
This driver should work with at least the following devices:
* Aten UC210T
* ASIX AX88172
* Billionton Systems, USB2AR
* Buffalo LUA-U2-KTX
* Corega FEther USB2-TX
* D-Link DUB-E100
* Hawking UF200
* Linksys USB200M
* Netgear FA120
* Sitecom LN-029
* Intellinet USB 2.0 Ethernet
* ST Lab USB 2.0 Ethernet
* TrendNet TU2-ET100
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use.
config USB_NET_CDCETHER
tristate "CDC Ethernet support (smart devices such as cable modems)"
depends on USB_USBNET
default y
help
Choose this option if you're using a host-to-host cable
based on this design, which supports USB 2.0 high speed.
This option supports devices conforming to the Communication Device
Class (CDC) Ethernet Control Model, a specification that's easy to
implement in device firmware. The CDC specifications are available
from <http://www.usb.org/>.
config USB_AN2720
boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
depends on USB_USBNET
default y
help
Choose this option if you're using a host-to-host cable
based on this design. Note that AnchorChips is now a
Cypress brand.
CDC Ethernet is an implementation option for DOCSIS cable modems
that support USB connectivity, used for non-Microsoft USB hosts.
The Linux-USB CDC Ethernet Gadget driver is an open implementation.
This driver should work with at least the following devices:
config USB_BELKIN
boolean "eTEK based host-to-host cables (Advance, Belkin, ...)"
depends on USB_USBNET
default y
help
Choose this option if you're using a host-to-host cable
based on this design: two NetChip 2890 chips and an Atmel
microcontroller, with LEDs that indicate traffic.
* Ericsson PipeRider (all variants)
* Motorola (DM100 and SB4100)
* Broadcom Cable Modem (reference design)
* Toshiba PCX1100U
* ...
config USB_GENESYS
boolean "GeneSys GL620USB-A based cables"
default y
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use. However, if the
IEEE 802 "local assignment" bit is set in the address, a "usbX"
name is used instead.
config USB_NET_GL620A
tristate "GeneSys GL620USB-A based cables"
depends on USB_USBNET
help
Choose this option if you're using a host-to-host cable,
@ -164,38 +189,78 @@ config USB_GENESYS
Note that the half-duplex "GL620USB" is not supported.
config USB_NET1080
boolean "NetChip 1080 based cables (Laplink, ...)"
config USB_NET_NET1080
tristate "NetChip 1080 based cables (Laplink, ...)"
default y
depends on USB_USBNET
help
Choose this option if you're using a host-to-host cable based
on this design: one NetChip 1080 chips and supporting logic,
supporting LEDs that indicate traffic
on this design: one NetChip 1080 chip and supporting logic,
optionally with LEDs that indicate traffic
config USB_PL2301
boolean "Prolific PL-2301/2302 based cables"
default y
# handshake/init/reset problems, from original 'plusb' driver
config USB_NET_PLUSB
tristate "Prolific PL-2301/2302 based cables"
# if the handshake/init/reset problems, from original 'plusb',
# are ever resolved ... then remove "experimental"
depends on USB_USBNET && EXPERIMENTAL
help
Choose this option if you're using a host-to-host cable
with one of these chips.
config USB_KC2190
boolean "KT Technology KC2190 based cables (InstaNet)"
default y
config USB_NET_RNDIS_HOST
tristate "Host for RNDIS devices (EXPERIMENTAL)"
depends on USB_USBNET && EXPERIMENTAL
select USB_NET_CDCETHER
help
Choose this option if you're using a host-to-host cable
with one of these chips.
This option enables hosting "Remote NDIS" USB networking links,
as encouraged by Microsoft (instead of CDC Ethernet!) for use in
various devices that may only support this protocol.
comment "Intelligent USB Devices/Gadgets"
Avoid using this protocol unless you have no better options.
The protocol specification is incomplete, and is controlled by
(and for) Microsoft; it isn't an "Open" ecosystem or market.
config USB_NET_CDC_SUBSET
tristate "Simple USB Network Links (CDC Ethernet subset)"
depends on USB_USBNET
help
This driver module supports USB network devices that can work
without any device-specific information. Select it if you have
one of these drivers.
Note that while many USB host-to-host cables can work in this mode,
that may mean not being able to talk to Win32 systems or more
commonly not being able to handle certain events (like replugging
the host on the other end) very well. Also, these devices will
not generally have permanently assigned Ethernet addresses.
config USB_ALI_M5632
boolean "ALi M5632 based 'USB 2.0 Data Link' cables"
depends on USB_NET_CDC_SUBSET
help
Choose this option if you're using a host-to-host cable
based on this design, which supports USB 2.0 high speed.
config USB_AN2720
boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
depends on USB_NET_CDC_SUBSET
help
Choose this option if you're using a host-to-host cable
based on this design. Note that AnchorChips is now a
Cypress brand.
config USB_BELKIN
boolean "eTEK based host-to-host cables (Advance, Belkin, ...)"
depends on USB_NET_CDC_SUBSET
default y
help
Choose this option if you're using a host-to-host cable
based on this design: two NetChip 2890 chips and an Atmel
microcontroller, with LEDs that indicate traffic.
config USB_ARMLINUX
boolean "Embedded ARM Linux links (iPaq, ...)"
depends on USB_USBNET
depends on USB_NET_CDC_SUBSET
default y
help
Choose this option to support the "usb-eth" networking driver
@ -212,15 +277,15 @@ config USB_ARMLINUX
config USB_EPSON2888
boolean "Epson 2888 based firmware (DEVELOPMENT)"
depends on USB_USBNET
default y
depends on USB_NET_CDC_SUBSET
help
Choose this option to support the usb networking links used
by some sample firmware from Epson.
config USB_ZAURUS
boolean "Sharp Zaurus (stock ROMs) and compatible"
config USB_NET_ZAURUS
tristate "Sharp Zaurus (stock ROMs) and compatible"
depends on USB_USBNET
select USB_NET_CDCETHER
select CRC32
default y
help
@ -235,61 +300,6 @@ config USB_ZAURUS
really need this non-conformant variant of CDC Ethernet (or in
some cases CDC MDLM) protocol, not "g_ether".
config USB_CDCETHER
boolean "CDC Ethernet support (smart devices such as cable modems)"
depends on USB_USBNET
default y
help
This option supports devices conforming to the Communication Device
Class (CDC) Ethernet Control Model, a specification that's easy to
implement in device firmware. The CDC specifications are available
from <http://www.usb.org/>.
CDC Ethernet is an implementation option for DOCSIS cable modems
that support USB connectivity, used for non-Microsoft USB hosts.
This driver should work with at least the following devices:
* Ericsson PipeRider (all variants)
* Motorola (DM100 and SB4100)
* Broadcom Cable Modem (reference design)
* Toshiba PCX1100U
* ...
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use. However, if the
IEEE 802 "local assignment" bit is set in the address, a "usbX"
name is used instead.
comment "USB Network Adapters"
depends on USB_USBNET
config USB_AX8817X
boolean "ASIX AX88xxx Based USB 2.0 Ethernet Devices"
depends on USB_USBNET && NET_ETHERNET
select CRC32
select MII
default y
help
This option adds support for ASIX AX88xxx based USB 2.0
10/100 Ethernet devices.
This driver should work with at least the following devices:
* Aten UC210T
* ASIX AX88172
* Billionton Systems, USB2AR
* Buffalo LUA-U2-KTX
* Corega FEther USB2-TX
* D-Link DUB-E100
* Hawking UF200
* Linksys USB200M
* Netgear FA120
* Sitecom LN-029
* Intellinet USB 2.0 Ethernet
* ST Lab USB 2.0 Ethernet
* TrendNet TU2-ET100
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use.
config USB_ZD1201
tristate "USB ZD1201 based Wireless device support"

View file

@ -6,5 +6,13 @@ obj-$(CONFIG_USB_CATC) += catc.o
obj-$(CONFIG_USB_KAWETH) += kaweth.o
obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
obj-$(CONFIG_USB_NET_NET1080) += net1080.o
obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o
obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o
obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
obj-$(CONFIG_USB_ZD1201) += zd1201.o

948
drivers/usb/net/asix.c Normal file
View file

@ -0,0 +1,948 @@
/*
* ASIX AX8817X based USB 2.0 Ethernet Devices
* Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
* Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
* Copyright (c) 2002-2003 TiVo Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#endif
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/crc32.h>
#include "usbnet.h"
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
#define AX_CMD_SET_SW_MII 0x06
#define AX_CMD_READ_MII_REG 0x07
#define AX_CMD_WRITE_MII_REG 0x08
#define AX_CMD_SET_HW_MII 0x0a
#define AX_CMD_READ_EEPROM 0x0b
#define AX_CMD_WRITE_EEPROM 0x0c
#define AX_CMD_WRITE_ENABLE 0x0d
#define AX_CMD_WRITE_DISABLE 0x0e
#define AX_CMD_WRITE_RX_CTL 0x10
#define AX_CMD_READ_IPG012 0x11
#define AX_CMD_WRITE_IPG0 0x12
#define AX_CMD_WRITE_IPG1 0x13
#define AX_CMD_WRITE_IPG2 0x14
#define AX_CMD_WRITE_MULTI_FILTER 0x16
#define AX_CMD_READ_NODE_ID 0x17
#define AX_CMD_READ_PHY_ID 0x19
#define AX_CMD_READ_MEDIUM_STATUS 0x1a
#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
#define AX_CMD_READ_MONITOR_MODE 0x1c
#define AX_CMD_WRITE_MONITOR_MODE 0x1d
#define AX_CMD_WRITE_GPIOS 0x1f
#define AX_CMD_SW_RESET 0x20
#define AX_CMD_SW_PHY_STATUS 0x21
#define AX_CMD_SW_PHY_SELECT 0x22
#define AX88772_CMD_READ_NODE_ID 0x13
#define AX_MONITOR_MODE 0x01
#define AX_MONITOR_LINK 0x02
#define AX_MONITOR_MAGIC 0x04
#define AX_MONITOR_HSFS 0x10
/* AX88172 Medium Status Register values */
#define AX_MEDIUM_FULL_DUPLEX 0x02
#define AX_MEDIUM_TX_ABORT_ALLOW 0x04
#define AX_MEDIUM_FLOW_CONTROL_EN 0x10
#define AX_MCAST_FILTER_SIZE 8
#define AX_MAX_MCAST 64
#define AX_EEPROM_LEN 0x40
#define AX_SWRESET_CLEAR 0x00
#define AX_SWRESET_RR 0x01
#define AX_SWRESET_RT 0x02
#define AX_SWRESET_PRTE 0x04
#define AX_SWRESET_PRL 0x08
#define AX_SWRESET_BZ 0x10
#define AX_SWRESET_IPRL 0x20
#define AX_SWRESET_IPPD 0x40
#define AX88772_IPG0_DEFAULT 0x15
#define AX88772_IPG1_DEFAULT 0x0c
#define AX88772_IPG2_DEFAULT 0x12
#define AX88772_MEDIUM_FULL_DUPLEX 0x0002
#define AX88772_MEDIUM_RESERVED 0x0004
#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010
#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020
#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080
#define AX88772_MEDIUM_RX_ENABLE 0x0100
#define AX88772_MEDIUM_100MB 0x0200
#define AX88772_MEDIUM_DEFAULT \
(AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \
AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \
AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE )
#define AX_EEPROM_MAGIC 0xdeadbeef
/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
struct ax8817x_data {
u8 multi_filter[AX_MCAST_FILTER_SIZE];
};
struct ax88172_int_data {
u16 res1;
u8 link;
u16 res2;
u8 status;
u16 res3;
} __attribute__ ((packed));
static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
return usb_control_msg(
dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
cmd,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value,
index,
data,
size,
USB_CTRL_GET_TIMEOUT);
}
static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
return usb_control_msg(
dev->udev,
usb_sndctrlpipe(dev->udev, 0),
cmd,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value,
index,
data,
size,
USB_CTRL_SET_TIMEOUT);
}
static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
if (urb->status < 0)
printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d",
urb->status);
kfree(req);
usb_free_urb(urb);
}
static void ax8817x_status(struct usbnet *dev, struct urb *urb)
{
struct ax88172_int_data *event;
int link;
if (urb->actual_length < 8)
return;
event = urb->transfer_buffer;
link = event->link & 0x01;
if (netif_carrier_ok(dev->net) != link) {
if (link) {
netif_carrier_on(dev->net);
usbnet_defer_kevent (dev, EVENT_LINK_RESET );
} else
netif_carrier_off(dev->net);
devdbg(dev, "ax8817x - Link Status is: %d", link);
}
}
static void
ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
struct usb_ctrlrequest *req;
int status;
struct urb *urb;
if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
devdbg(dev, "Error allocating URB in write_cmd_async!");
return;
}
if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
deverr(dev, "Failed to allocate memory for control request");
usb_free_urb(urb);
return;
}
req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
req->bRequest = cmd;
req->wValue = cpu_to_le16(value);
req->wIndex = cpu_to_le16(index);
req->wLength = cpu_to_le16(size);
usb_fill_control_urb(urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0),
(void *)req, data, size,
ax8817x_async_cmd_callback, req);
if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
deverr(dev, "Error submitting the control message: status=%d",
status);
kfree(req);
usb_free_urb(urb);
}
}
static void ax8817x_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
u8 rx_ctl = 0x8c;
if (net->flags & IFF_PROMISC) {
rx_ctl |= 0x01;
} else if (net->flags & IFF_ALLMULTI
|| net->mc_count > AX_MAX_MCAST) {
rx_ctl |= 0x02;
} else if (net->mc_count == 0) {
/* just broadcast and directed */
} else {
/* We use the 20 byte dev->data
* for our 8 byte filter buffer
* to avoid allocating memory that
* is tricky to free later */
struct dev_mc_list *mc_list = net->mc_list;
u32 crc_bits;
int i;
memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
/* Build the multicast hash filter. */
for (i = 0; i < net->mc_count; i++) {
crc_bits =
ether_crc(ETH_ALEN,
mc_list->dmi_addr) >> 26;
data->multi_filter[crc_bits >> 3] |=
1 << (crc_bits & 7);
mc_list = mc_list->next;
}
ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
AX_MCAST_FILTER_SIZE, data->multi_filter);
rx_ctl |= 0x10;
}
ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
}
static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc)
{
struct usbnet *dev = netdev_priv(netdev);
u16 res;
u8 buf[1];
ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf);
ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
(__u16)loc, 2, (u16 *)&res);
ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
return res & 0xffff;
}
/* same as above, but converts resulting value to cpu byte order */
static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc)
{
return le16_to_cpu(ax8817x_mdio_read(netdev,phy_id, loc));
}
static void
ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
{
struct usbnet *dev = netdev_priv(netdev);
u16 res = val;
u8 buf[1];
ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf);
ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
(__u16)loc, 2, (u16 *)&res);
ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
}
/* same as above, but converts new value to le16 byte order before writing */
static void
ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val)
{
ax8817x_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
}
static int ax88172_link_reset(struct usbnet *dev)
{
u16 lpa;
u16 adv;
u16 res;
u8 mode;
mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
res = mii_nway_result(lpa|adv);
if (res & LPA_DUPLEX)
mode |= AX_MEDIUM_FULL_DUPLEX;
ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
return 0;
}
static void
ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
{
struct usbnet *dev = netdev_priv(net);
u8 opt;
if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
wolinfo->supported = 0;
wolinfo->wolopts = 0;
return;
}
wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
wolinfo->wolopts = 0;
if (opt & AX_MONITOR_MODE) {
if (opt & AX_MONITOR_LINK)
wolinfo->wolopts |= WAKE_PHY;
if (opt & AX_MONITOR_MAGIC)
wolinfo->wolopts |= WAKE_MAGIC;
}
}
static int
ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
{
struct usbnet *dev = netdev_priv(net);
u8 opt = 0;
u8 buf[1];
if (wolinfo->wolopts & WAKE_PHY)
opt |= AX_MONITOR_LINK;
if (wolinfo->wolopts & WAKE_MAGIC)
opt |= AX_MONITOR_MAGIC;
if (opt != 0)
opt |= AX_MONITOR_MODE;
if (ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
opt, 0, 0, &buf) < 0)
return -EINVAL;
return 0;
}
static int ax8817x_get_eeprom_len(struct net_device *net)
{
return AX_EEPROM_LEN;
}
static int ax8817x_get_eeprom(struct net_device *net,
struct ethtool_eeprom *eeprom, u8 *data)
{
struct usbnet *dev = netdev_priv(net);
u16 *ebuf = (u16 *)data;
int i;
/* Crude hack to ensure that we don't overwrite memory
* if an odd length is supplied
*/
if (eeprom->len % 2)
return -EINVAL;
eeprom->magic = AX_EEPROM_MAGIC;
/* ax8817x returns 2 bytes from eeprom on read */
for (i=0; i < eeprom->len / 2; i++) {
if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM,
eeprom->offset + i, 0, 2, &ebuf[i]) < 0)
return -EINVAL;
}
return 0;
}
static void ax8817x_get_drvinfo (struct net_device *net,
struct ethtool_drvinfo *info)
{
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
info->eedump_len = 0x3e;
}
static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
return mii_ethtool_gset(&dev->mii,cmd);
}
static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
return mii_ethtool_sset(&dev->mii,cmd);
}
/* We need to override some ethtool_ops so we require our
own structure so we don't interfere with other usbnet
devices that may be connected at the same time. */
static struct ethtool_ops ax8817x_ethtool_ops = {
.get_drvinfo = ax8817x_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = ax8817x_get_wol,
.set_wol = ax8817x_set_wol,
.get_eeprom_len = ax8817x_get_eeprom_len,
.get_eeprom = ax8817x_get_eeprom,
.get_settings = ax8817x_get_settings,
.set_settings = ax8817x_set_settings,
};
static int ax8817x_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret = 0;
void *buf;
int i;
unsigned long gpio_bits = dev->driver_info->data;
usbnet_get_endpoints(dev,intf);
buf = kmalloc(ETH_ALEN, GFP_KERNEL);
if(!buf) {
ret = -ENOMEM;
goto out1;
}
/* Toggle the GPIOs in a manufacturer/model specific way */
for (i = 2; i >= 0; i--) {
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
(gpio_bits >> (i * 8)) & 0xff, 0, 0,
buf)) < 0)
goto out2;
msleep(5);
}
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
0x80, 0, 0, buf)) < 0) {
dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret);
goto out2;
}
/* Get the MAC address */
memset(buf, 0, ETH_ALEN);
if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID,
0, 0, 6, buf)) < 0) {
dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
goto out2;
}
memcpy(dev->net->dev_addr, buf, ETH_ALEN);
/* Get the PHY id */
if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID,
0, 0, 2, buf)) < 0) {
dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret);
goto out2;
} else if (ret < 2) {
/* this should always return 2 bytes */
dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x",
ret);
ret = -EIO;
goto out2;
}
/* Initialize MII structure */
dev->mii.dev = dev->net;
dev->mii.mdio_read = ax8817x_mdio_read;
dev->mii.mdio_write = ax8817x_mdio_write;
dev->mii.phy_id_mask = 0x3f;
dev->mii.reg_num_mask = 0x1f;
dev->mii.phy_id = *((u8 *)buf + 1);
dev->net->do_ioctl = ax8817x_ioctl;
dev->net->set_multicast_list = ax8817x_set_multicast;
dev->net->ethtool_ops = &ax8817x_ethtool_ops;
ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
mii_nway_restart(&dev->mii);
return 0;
out2:
kfree(buf);
out1:
return ret;
}
static struct ethtool_ops ax88772_ethtool_ops = {
.get_drvinfo = ax8817x_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = ax8817x_get_wol,
.set_wol = ax8817x_set_wol,
.get_eeprom_len = ax8817x_get_eeprom_len,
.get_eeprom = ax8817x_get_eeprom,
.get_settings = ax8817x_get_settings,
.set_settings = ax8817x_set_settings,
};
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
void *buf;
usbnet_get_endpoints(dev,intf);
buf = kmalloc(6, GFP_KERNEL);
if(!buf) {
dbg ("Cannot allocate memory for buffer");
ret = -ENOMEM;
goto out1;
}
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
0x00B0, 0, 0, buf)) < 0)
goto out2;
msleep(5);
if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
0x0001, 0, 0, buf)) < 0) {
dbg("Select PHY #1 failed: %d", ret);
goto out2;
}
if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD,
0, 0, buf)) < 0) {
dbg("Failed to power down internal PHY: %d", ret);
goto out2;
}
msleep(150);
if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR,
0, 0, buf)) < 0) {
dbg("Failed to perform software reset: %d", ret);
goto out2;
}
msleep(150);
if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
AX_SWRESET_IPRL | AX_SWRESET_PRL,
0, 0, buf)) < 0) {
dbg("Failed to set Internal/External PHY reset control: %d",
ret);
goto out2;
}
msleep(150);
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
0x0000, 0, 0, buf)) < 0) {
dbg("Failed to reset RX_CTL: %d", ret);
goto out2;
}
/* Get the MAC address */
memset(buf, 0, ETH_ALEN);
if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID,
0, 0, ETH_ALEN, buf)) < 0) {
dbg("Failed to read MAC address: %d", ret);
goto out2;
}
memcpy(dev->net->dev_addr, buf, ETH_ALEN);
if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII,
0, 0, 0, buf)) < 0) {
dbg("Enabling software MII failed: %d", ret);
goto out2;
}
if (((ret = ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG,
0x0010, 2, 2, buf)) < 0)
|| (*((u16 *)buf) != 0x003b)) {
dbg("Read PHY register 2 must be 0x3b00: %d", ret);
goto out2;
}
/* Initialize MII structure */
dev->mii.dev = dev->net;
dev->mii.mdio_read = ax8817x_mdio_read;
dev->mii.mdio_write = ax8817x_mdio_write;
dev->mii.phy_id_mask = 0xff;
dev->mii.reg_num_mask = 0xff;
dev->net->do_ioctl = ax8817x_ioctl;
/* Get the PHY id */
if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID,
0, 0, 2, buf)) < 0) {
dbg("Error reading PHY ID: %02x", ret);
goto out2;
} else if (ret < 2) {
/* this should always return 2 bytes */
dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x",
ret);
ret = -EIO;
goto out2;
}
dev->mii.phy_id = *((u8 *)buf + 1);
if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL,
0, 0, buf)) < 0) {
dbg("Set external PHY reset pin level: %d", ret);
goto out2;
}
msleep(150);
if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
AX_SWRESET_IPRL | AX_SWRESET_PRL,
0, 0, buf)) < 0) {
dbg("Set Internal/External PHY reset control: %d", ret);
goto out2;
}
msleep(150);
dev->net->set_multicast_list = ax8817x_set_multicast;
dev->net->ethtool_ops = &ax88772_ethtool_ops;
ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA);
mii_nway_restart(&dev->mii);
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) {
dbg("Write medium mode register: %d", ret);
goto out2;
}
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
AX88772_IPG2_DEFAULT, 0, buf)) < 0) {
dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
goto out2;
}
if ((ret =
ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) {
dbg("Failed to set hardware MII: %02x", ret);
goto out2;
}
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
if ((ret =
ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0,
buf)) < 0) {
dbg("Reset RX_CTL failed: %d", ret);
goto out2;
}
kfree(buf);
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
if (dev->driver_info->flags & FLAG_FRAMING_AX) {
/* hard_mtu is still the default - the device does not support
jumbo eth frames */
dev->rx_urb_size = 2048;
}
return 0;
out2:
kfree(buf);
out1:
return ret;
}
static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
u8 *head;
u32 header;
char *packet;
struct sk_buff *ax_skb;
u16 size;
head = (u8 *) skb->data;
memcpy(&header, head, sizeof(header));
le32_to_cpus(&header);
packet = head + sizeof(header);
skb_pull(skb, 4);
while (skb->len > 0) {
if ((short)(header & 0x0000ffff) !=
~((short)((header & 0xffff0000) >> 16))) {
devdbg(dev,"header length data is error");
}
/* get the packet length */
size = (u16) (header & 0x0000ffff);
if ((skb->len) - ((size + 1) & 0xfffe) == 0)
return 2;
if (size > ETH_FRAME_LEN) {
devdbg(dev,"invalid rx length %d", size);
return 0;
}
ax_skb = skb_clone(skb, GFP_ATOMIC);
if (ax_skb) {
ax_skb->len = size;
ax_skb->data = packet;
ax_skb->tail = packet + size;
usbnet_skb_return(dev, ax_skb);
} else {
return 0;
}
skb_pull(skb, (size + 1) & 0xfffe);
if (skb->len == 0)
break;
head = (u8 *) skb->data;
memcpy(&header, head, sizeof(header));
le32_to_cpus(&header);
packet = head + sizeof(header);
skb_pull(skb, 4);
}
if (skb->len < 0) {
devdbg(dev,"invalid rx length %d", skb->len);
return 0;
}
return 1;
}
static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
unsigned flags)
{
int padlen;
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
u32 packet_len;
u32 padbytes = 0xffff0000;
padlen = ((skb->len + 4) % 512) ? 0 : 4;
if ((!skb_cloned(skb))
&& ((headroom + tailroom) >= (4 + padlen))) {
if ((headroom < 4) || (tailroom < padlen)) {
skb->data = memmove(skb->head + 4, skb->data, skb->len);
skb->tail = skb->data + skb->len;
}
} else {
struct sk_buff *skb2;
skb2 = skb_copy_expand(skb, 4, padlen, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (!skb)
return NULL;
}
skb_push(skb, 4);
packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
memcpy(skb->data, &packet_len, sizeof(packet_len));
if ((skb->len % 512) == 0) {
memcpy( skb->tail, &padbytes, sizeof(padbytes));
skb_put(skb, sizeof(padbytes));
}
return skb;
}
static int ax88772_link_reset(struct usbnet *dev)
{
u16 lpa;
u16 adv;
u16 res;
u16 mode;
mode = AX88772_MEDIUM_DEFAULT;
lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
res = mii_nway_result(lpa|adv);
if ((res & LPA_DUPLEX) == 0)
mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
if ((res & LPA_100) == 0)
mode &= ~AX88772_MEDIUM_100MB;
ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
return 0;
}
static const struct driver_info ax8817x_info = {
.description = "ASIX AX8817x USB 2.0 Ethernet",
.bind = ax8817x_bind,
.status = ax8817x_status,
.link_reset = ax88172_link_reset,
.reset = ax88172_link_reset,
.flags = FLAG_ETHER,
.data = 0x00130103,
};
static const struct driver_info dlink_dub_e100_info = {
.description = "DLink DUB-E100 USB Ethernet",
.bind = ax8817x_bind,
.status = ax8817x_status,
.link_reset = ax88172_link_reset,
.reset = ax88172_link_reset,
.flags = FLAG_ETHER,
.data = 0x009f9d9f,
};
static const struct driver_info netgear_fa120_info = {
.description = "Netgear FA-120 USB Ethernet",
.bind = ax8817x_bind,
.status = ax8817x_status,
.link_reset = ax88172_link_reset,
.reset = ax88172_link_reset,
.flags = FLAG_ETHER,
.data = 0x00130103,
};
static const struct driver_info hawking_uf200_info = {
.description = "Hawking UF200 USB Ethernet",
.bind = ax8817x_bind,
.status = ax8817x_status,
.link_reset = ax88172_link_reset,
.reset = ax88172_link_reset,
.flags = FLAG_ETHER,
.data = 0x001f1d1f,
};
static const struct driver_info ax88772_info = {
.description = "ASIX AX88772 USB 2.0 Ethernet",
.bind = ax88772_bind,
.status = ax8817x_status,
.link_reset = ax88772_link_reset,
.reset = ax88772_link_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX,
.rx_fixup = ax88772_rx_fixup,
.tx_fixup = ax88772_tx_fixup,
.data = 0x00130103,
};
static const struct usb_device_id products [] = {
{
// Linksys USB200M
USB_DEVICE (0x077b, 0x2226),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// Netgear FA120
USB_DEVICE (0x0846, 0x1040),
.driver_info = (unsigned long) &netgear_fa120_info,
}, {
// DLink DUB-E100
USB_DEVICE (0x2001, 0x1a00),
.driver_info = (unsigned long) &dlink_dub_e100_info,
}, {
// Intellinet, ST Lab USB Ethernet
USB_DEVICE (0x0b95, 0x1720),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// Hawking UF200, TrendNet TU2-ET100
USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info,
}, {
// Billionton Systems, USB2AR
USB_DEVICE (0x08dd, 0x90ff),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// ATEN UC210T
USB_DEVICE (0x0557, 0x2009),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// Buffalo LUA-U2-KTX
USB_DEVICE (0x0411, 0x003d),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter"
USB_DEVICE (0x6189, 0x182d),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// corega FEther USB2-TX
USB_DEVICE (0x07aa, 0x0017),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// Surecom EP-1427X-2
USB_DEVICE (0x1189, 0x0893),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// goodway corp usb gwusb2e
USB_DEVICE (0x1631, 0x6200),
.driver_info = (unsigned long) &ax8817x_info,
}, {
// ASIX AX88772 10/100
USB_DEVICE (0x0b95, 0x7720),
.driver_info = (unsigned long) &ax88772_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver asix_driver = {
.owner = THIS_MODULE,
.name = "asix",
.id_table = products,
.probe = usbnet_probe,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
};
static int __init asix_init(void)
{
return usb_register(&asix_driver);
}
module_init(asix_init);
static void __exit asix_exit(void)
{
usb_deregister(&asix_driver);
}
module_exit(asix_exit);
MODULE_AUTHOR("David Hollis");
MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices");
MODULE_LICENSE("GPL");

View file

@ -383,7 +383,6 @@ static void catc_tx_done(struct urb *urb, struct pt_regs *regs)
if (urb->status == -ECONNRESET) {
dbg("Tx Reset.");
urb->transfer_flags &= ~URB_ASYNC_UNLINK;
urb->status = 0;
catc->netdev->trans_start = jiffies;
catc->stats.tx_errors++;
@ -445,7 +444,6 @@ static void catc_tx_timeout(struct net_device *netdev)
struct catc *catc = netdev_priv(netdev);
warn("Transmit timed out.");
catc->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_unlink_urb(catc->tx_urb);
}

509
drivers/usb/net/cdc_ether.c Normal file
View file

@ -0,0 +1,509 @@
/*
* CDC Ethernet based networking peripherals
* Copyright (C) 2003-2005 by David Brownell
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ctype.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb_cdc.h>
#include "usbnet.h"
/*
* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
* all pure cdc, except for certain firmware workarounds, and knowing
* that rndis uses one different rule.
*/
int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
{
u8 *buf = intf->cur_altsetting->extra;
int len = intf->cur_altsetting->extralen;
struct usb_interface_descriptor *d;
struct cdc_state *info = (void *) &dev->data;
int status;
int rndis;
struct usb_driver *driver = driver_of(intf);
if (sizeof dev->data < sizeof *info)
return -EDOM;
/* expect strict spec conformance for the descriptors, but
* cope with firmware which stores them in the wrong place
*/
if (len == 0 && dev->udev->actconfig->extralen) {
/* Motorola SB4100 (and others: Brad Hards says it's
* from a Broadcom design) put CDC descriptors here
*/
buf = dev->udev->actconfig->extra;
len = dev->udev->actconfig->extralen;
if (len)
dev_dbg(&intf->dev,
"CDC descriptors on config\n");
}
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
memset(info, 0, sizeof *info);
info->control = intf;
while (len > 3) {
if (buf [1] != USB_DT_CS_INTERFACE)
goto next_desc;
/* use bDescriptorSubType to identify the CDC descriptors.
* We expect devices with CDC header and union descriptors.
* For CDC Ethernet we need the ethernet descriptor.
* For RNDIS, ignore two (pointless) CDC modem descriptors
* in favor of a complicated OID-based RPC scheme doing what
* CDC Ethernet achieves with a simple descriptor.
*/
switch (buf [2]) {
case USB_CDC_HEADER_TYPE:
if (info->header) {
dev_dbg(&intf->dev, "extra CDC header\n");
goto bad_desc;
}
info->header = (void *) buf;
if (info->header->bLength != sizeof *info->header) {
dev_dbg(&intf->dev, "CDC header len %u\n",
info->header->bLength);
goto bad_desc;
}
break;
case USB_CDC_UNION_TYPE:
if (info->u) {
dev_dbg(&intf->dev, "extra CDC union\n");
goto bad_desc;
}
info->u = (void *) buf;
if (info->u->bLength != sizeof *info->u) {
dev_dbg(&intf->dev, "CDC union len %u\n",
info->u->bLength);
goto bad_desc;
}
/* we need a master/control interface (what we're
* probed with) and a slave/data interface; union
* descriptors sort this all out.
*/
info->control = usb_ifnum_to_if(dev->udev,
info->u->bMasterInterface0);
info->data = usb_ifnum_to_if(dev->udev,
info->u->bSlaveInterface0);
if (!info->control || !info->data) {
dev_dbg(&intf->dev,
"master #%u/%p slave #%u/%p\n",
info->u->bMasterInterface0,
info->control,
info->u->bSlaveInterface0,
info->data);
goto bad_desc;
}
if (info->control != intf) {
dev_dbg(&intf->dev, "bogus CDC Union\n");
/* Ambit USB Cable Modem (and maybe others)
* interchanges master and slave interface.
*/
if (info->data == intf) {
info->data = info->control;
info->control = intf;
} else
goto bad_desc;
}
/* a data interface altsetting does the real i/o */
d = &info->data->cur_altsetting->desc;
if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
dev_dbg(&intf->dev, "slave class %u\n",
d->bInterfaceClass);
goto bad_desc;
}
break;
case USB_CDC_ETHERNET_TYPE:
if (info->ether) {
dev_dbg(&intf->dev, "extra CDC ether\n");
goto bad_desc;
}
info->ether = (void *) buf;
if (info->ether->bLength != sizeof *info->ether) {
dev_dbg(&intf->dev, "CDC ether len %u\n",
info->ether->bLength);
goto bad_desc;
}
dev->hard_mtu = le16_to_cpu(
info->ether->wMaxSegmentSize);
/* because of Zaurus, we may be ignoring the host
* side link address we were given.
*/
break;
}
next_desc:
len -= buf [0]; /* bLength */
buf += buf [0];
}
if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ",
info->u ? "" : "union ",
info->ether ? "" : "ether ");
goto bad_desc;
}
/* claim data interface and set it up ... with side effects.
* network traffic can't flow until an altsetting is enabled.
*/
status = usb_driver_claim_interface(driver, info->data, dev);
if (status < 0)
return status;
status = usbnet_get_endpoints(dev, info->data);
if (status < 0) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver, info->data);
return status;
}
/* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
dev->status = NULL;
if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
struct usb_endpoint_descriptor *desc;
dev->status = &info->control->cur_altsetting->endpoint [0];
desc = &dev->status->desc;
if (desc->bmAttributes != USB_ENDPOINT_XFER_INT
|| !(desc->bEndpointAddress & USB_DIR_IN)
|| (le16_to_cpu(desc->wMaxPacketSize)
< sizeof(struct usb_cdc_notification))
|| !desc->bInterval) {
dev_dbg(&intf->dev, "bad notification endpoint\n");
dev->status = NULL;
}
}
if (rndis && !dev->status) {
dev_dbg(&intf->dev, "missing RNDIS status endpoint\n");
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver, info->data);
return -ENODEV;
}
return 0;
bad_desc:
dev_info(&dev->udev->dev, "bad CDC descriptors\n");
return -ENODEV;
}
EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind);
void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
{
struct cdc_state *info = (void *) &dev->data;
struct usb_driver *driver = driver_of(intf);
/* disconnect master --> disconnect slave */
if (intf == info->control && info->data) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver, info->data);
info->data = NULL;
}
/* and vice versa (just in case) */
else if (intf == info->data && info->control) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->control, NULL);
usb_driver_release_interface(driver, info->control);
info->control = NULL;
}
}
EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
/*-------------------------------------------------------------------------
*
* Communications Device Class, Ethernet Control model
*
* Takes two interfaces. The DATA interface is inactive till an altsetting
* is selected. Configuration data includes class descriptors. There's
* an optional status endpoint on the control interface.
*
* This should interop with whatever the 2.4 "CDCEther.c" driver
* (by Brad Hards) talked with, with more functionality.
*
*-------------------------------------------------------------------------*/
static void dumpspeed(struct usbnet *dev, __le32 *speeds)
{
if (netif_msg_timer(dev))
devinfo(dev, "link speeds: %u kbps up, %u kbps down",
__le32_to_cpu(speeds[0]) / 1000,
__le32_to_cpu(speeds[1]) / 1000);
}
static void cdc_status(struct usbnet *dev, struct urb *urb)
{
struct usb_cdc_notification *event;
if (urb->actual_length < sizeof *event)
return;
/* SPEED_CHANGE can get split into two 8-byte packets */
if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
dumpspeed(dev, (__le32 *) urb->transfer_buffer);
return;
}
event = urb->transfer_buffer;
switch (event->bNotificationType) {
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
if (netif_msg_timer(dev))
devdbg(dev, "CDC: carrier %s",
event->wValue ? "on" : "off");
if (event->wValue)
netif_carrier_on(dev->net);
else
netif_carrier_off(dev->net);
break;
case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */
if (netif_msg_timer(dev))
devdbg(dev, "CDC: speed change (len %d)",
urb->actual_length);
if (urb->actual_length != (sizeof *event + 8))
set_bit(EVENT_STS_SPLIT, &dev->flags);
else
dumpspeed(dev, (__le32 *) &event[1]);
break;
/* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS),
* but there are no standard formats for the response data.
*/
default:
deverr(dev, "CDC: unexpected notification %02x!",
event->bNotificationType);
break;
}
}
static u8 nibble(unsigned char c)
{
if (likely(isdigit(c)))
return c - '0';
c = toupper(c);
if (likely(isxdigit(c)))
return 10 + c - 'A';
return 0;
}
static inline int
get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e)
{
int tmp, i;
unsigned char buf [13];
tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf);
if (tmp != 12) {
dev_dbg(&dev->udev->dev,
"bad MAC string %d fetch, %d\n", e->iMACAddress, tmp);
if (tmp >= 0)
tmp = -EINVAL;
return tmp;
}
for (i = tmp = 0; i < 6; i++, tmp += 2)
dev->net->dev_addr [i] =
(nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]);
return 0;
}
static int cdc_bind(struct usbnet *dev, struct usb_interface *intf)
{
int status;
struct cdc_state *info = (void *) &dev->data;
status = usbnet_generic_cdc_bind(dev, intf);
if (status < 0)
return status;
status = get_ethernet_addr(dev, info->ether);
if (status < 0) {
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver_of(intf), info->data);
return status;
}
/* FIXME cdc-ether has some multicast code too, though it complains
* in routine cases. info->ether describes the multicast support.
* Implement that here, manipulating the cdc filter as needed.
*/
return 0;
}
static const struct driver_info cdc_info = {
.description = "CDC Ethernet Device",
.flags = FLAG_ETHER,
// .check_connect = cdc_check_connect,
.bind = cdc_bind,
.unbind = usbnet_cdc_unbind,
.status = cdc_status,
};
/*-------------------------------------------------------------------------*/
static const struct usb_device_id products [] = {
/*
* BLACKLIST !!
*
* First blacklist any products that are egregiously nonconformant
* with the CDC Ethernet specs. Minor braindamage we cope with; when
* they're not even trying, needing a separate driver is only the first
* of the differences to show up.
*/
#define ZAURUS_MASTER_INTERFACE \
.bInterfaceClass = USB_CLASS_COMM, \
.bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
.bInterfaceProtocol = USB_CDC_PROTO_NONE
/* SA-1100 based Sharp Zaurus ("collie"), or compatible;
* wire-incompatible with true CDC Ethernet implementations.
* (And, it seems, needlessly so...)
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8004,
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
},
/* PXA-25x based Sharp Zaurii. Note that it seems some of these
* (later models especially) may have shipped only with firmware
* advertising false "CDC MDLM" compatibility ... but we're not
* clear which models did that, so for now let's assume the worst.
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8005, /* A-300 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8006, /* B-500/SL-5600 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8007, /* C-700 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9031, /* C-750 C-760 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9032, /* SL-6000 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
/* reported with some C860 units */
.idProduct = 0x9050, /* C-860 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
},
/*
* WHITELIST!!!
*
* CDC Ether uses two interfaces, not necessarily consecutive.
* We match the main interface, ignoring the optional device
* class so we could handle devices that aren't exclusively
* CDC ether.
*
* NOTE: this match must come AFTER entries blacklisting devices
* because of bugs/quirks in a given product (like Zaurus, above).
*/
{
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &cdc_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver cdc_driver = {
.owner = THIS_MODULE,
.name = "cdc_ether",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init cdc_init(void)
{
BUG_ON((sizeof(((struct usbnet *)0)->data)
< sizeof(struct cdc_state)));
return usb_register(&cdc_driver);
}
module_init(cdc_init);
static void __exit cdc_exit(void)
{
usb_deregister(&cdc_driver);
}
module_exit(cdc_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("USB CDC Ethernet devices");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,335 @@
/*
* Simple "CDC Subset" USB Networking Links
* Copyright (C) 2000-2005 by David Brownell
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#endif
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include "usbnet.h"
/*
* This supports simple USB network links that don't require any special
* framing or hardware control operations. The protocol used here is a
* strict subset of CDC Ethernet, with three basic differences reflecting
* the goal that almost any hardware should run it:
*
* - Minimal runtime control: one interface, no altsettings, and
* no vendor or class specific control requests. If a device is
* configured, it is allowed to exchange packets with the host.
* Fancier models would mean not working on some hardware.
*
* - Minimal manufacturing control: no IEEE "Organizationally
* Unique ID" required, or an EEPROMs to store one. Each host uses
* one random "locally assigned" Ethernet address instead, which can
* of course be overridden using standard tools like "ifconfig".
* (With 2^46 such addresses, same-net collisions are quite rare.)
*
* - There is no additional framing data for USB. Packets are written
* exactly as in CDC Ethernet, starting with an Ethernet header and
* terminated by a short packet. However, the host will never send a
* zero length packet; some systems can't handle those robustly.
*
* Anything that can transmit and receive USB bulk packets can implement
* this protocol. That includes both smart peripherals and quite a lot
* of "host-to-host" USB cables (which embed two devices back-to-back).
*
* Note that although Linux may use many of those host-to-host links
* with this "cdc_subset" framing, that doesn't mean there may not be a
* better approach. Handling the "other end unplugs/replugs" scenario
* well tends to require chip-specific vendor requests. Also, Windows
* peers at the other end of host-to-host cables may expect their own
* framing to be used rather than this "cdc_subset" model.
*/
#if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX)
/* PDA style devices are always connected if present */
static int always_connected (struct usbnet *dev)
{
return 0;
}
#endif
#ifdef CONFIG_USB_ALI_M5632
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* ALi M5632 driver ... does high speed
*
*-------------------------------------------------------------------------*/
static const struct driver_info ali_m5632_info = {
.description = "ALi M5632",
};
#endif
#ifdef CONFIG_USB_AN2720
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* AnchorChips 2720 driver ... http://www.cypress.com
*
* This doesn't seem to have a way to detect whether the peer is
* connected, or need any reset handshaking. It's got pretty big
* internal buffers (handles most of a frame's worth of data).
* Chip data sheets don't describe any vendor control messages.
*
*-------------------------------------------------------------------------*/
static const struct driver_info an2720_info = {
.description = "AnchorChips/Cypress 2720",
// no reset available!
// no check_connect available!
.in = 2, .out = 2, // direction distinguishes these
};
#endif /* CONFIG_USB_AN2720 */
#ifdef CONFIG_USB_BELKIN
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller
*
* ... also two eTEK designs, including one sold as "Advance USBNET"
*
*-------------------------------------------------------------------------*/
static const struct driver_info belkin_info = {
.description = "Belkin, eTEK, or compatible",
};
#endif /* CONFIG_USB_BELKIN */
#ifdef CONFIG_USB_EPSON2888
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* EPSON USB clients
*
* This is the same idea as Linux PDAs (below) except the firmware in the
* device might not be Tux-powered. Epson provides reference firmware that
* implements this interface. Product developers can reuse or modify that
* code, such as by using their own product and vendor codes.
*
* Support was from Juro Bystricky <bystricky.juro@erd.epson.com>
*
*-------------------------------------------------------------------------*/
static const struct driver_info epson2888_info = {
.description = "Epson USB Device",
.check_connect = always_connected,
.in = 4, .out = 3,
};
#endif /* CONFIG_USB_EPSON2888 */
#ifdef CONFIG_USB_KC2190
#define HAVE_HARDWARE
static const struct driver_info kc2190_info = {
.description = "KC Technology KC-190",
};
#endif /* CONFIG_USB_KC2190 */
#ifdef CONFIG_USB_ARMLINUX
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* Intel's SA-1100 chip integrates basic USB support, and is used
* in PDAs like some iPaqs, the Yopy, some Zaurus models, and more.
* When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to
* network using minimal USB framing data.
*
* This describes the driver currently in standard ARM Linux kernels.
* The Zaurus uses a different driver (see later).
*
* PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support
* and different USB endpoint numbering than the SA1100 devices. The
* mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100
* so we rely on the endpoint descriptors.
*
*-------------------------------------------------------------------------*/
static const struct driver_info linuxdev_info = {
.description = "Linux Device",
.check_connect = always_connected,
};
static const struct driver_info yopy_info = {
.description = "Yopy",
.check_connect = always_connected,
};
static const struct driver_info blob_info = {
.description = "Boot Loader OBject",
.check_connect = always_connected,
};
#endif /* CONFIG_USB_ARMLINUX */
/*-------------------------------------------------------------------------*/
#ifndef HAVE_HARDWARE
#error You need to configure some hardware for this driver
#endif
/*
* chip vendor names won't normally be on the cables, and
* may not be on the device.
*/
static const struct usb_device_id products [] = {
#ifdef CONFIG_USB_ALI_M5632
{
USB_DEVICE (0x0402, 0x5632), // ALi defaults
.driver_info = (unsigned long) &ali_m5632_info,
},
#endif
#ifdef CONFIG_USB_AN2720
{
USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults
.driver_info = (unsigned long) &an2720_info,
}, {
USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET
.driver_info = (unsigned long) &an2720_info,
},
#endif
#ifdef CONFIG_USB_BELKIN
{
USB_DEVICE (0x050d, 0x0004), // Belkin
.driver_info = (unsigned long) &belkin_info,
}, {
USB_DEVICE (0x056c, 0x8100), // eTEK
.driver_info = (unsigned long) &belkin_info,
}, {
USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK)
.driver_info = (unsigned long) &belkin_info,
},
#endif
#ifdef CONFIG_USB_EPSON2888
{
USB_DEVICE (0x0525, 0x2888), // EPSON USB client
.driver_info = (unsigned long) &epson2888_info,
},
#endif
#ifdef CONFIG_USB_KC2190
{
USB_DEVICE (0x050f, 0x0190), // KC-190
.driver_info = (unsigned long) &kc2190_info,
},
#endif
#ifdef CONFIG_USB_ARMLINUX
/*
* SA-1100 using standard ARM Linux kernels, or compatible.
* Often used when talking to Linux PDAs (iPaq, Yopy, etc).
* The sa-1100 "usb-eth" driver handles the basic framing.
*
* PXA25x or PXA210 ... these use a "usb-eth" driver much like
* the sa1100 one, but hardware uses different endpoint numbers.
*
* Or the Linux "Ethernet" gadget on hardware that can't talk
* CDC Ethernet (e.g., no altsettings), in either of two modes:
* - acting just like the old "usb-eth" firmware, though
* the implementation is different
* - supporting RNDIS as the first/default configuration for
* MS-Windows interop; Linux needs to use the other config
*/
{
// 1183 = 0x049F, both used as hex values?
// Compaq "Itsy" vendor/product id
USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible
.driver_info = (unsigned long) &linuxdev_info,
}, {
USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy"
.driver_info = (unsigned long) &yopy_info,
}, {
USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader
.driver_info = (unsigned long) &blob_info,
}, {
// Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config
// e.g. Gumstix, current OpenZaurus, ...
USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203),
.driver_info = (unsigned long) &linuxdev_info,
},
#endif
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
/*-------------------------------------------------------------------------*/
static struct usb_driver cdc_subset_driver = {
.owner = THIS_MODULE,
.name = "cdc_subset",
.probe = usbnet_probe,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.id_table = products,
};
static int __init cdc_subset_init(void)
{
return usb_register(&cdc_subset_driver);
}
module_init(cdc_subset_init);
static void __exit cdc_subset_exit(void)
{
usb_deregister(&cdc_subset_driver);
}
module_exit(cdc_subset_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links");
MODULE_LICENSE("GPL");

407
drivers/usb/net/gl620a.c Normal file
View file

@ -0,0 +1,407 @@
/*
* GeneSys GL620USB-A based links
* Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
* Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include "usbnet.h"
/*
* GeneSys GL620USB-A (www.genesyslogic.com.tw)
*
* ... should partially interop with the Win32 driver for this hardware.
* The GeneSys docs imply there's some NDIS issue motivating this framing.
*
* Some info from GeneSys:
* - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
* (Some cables, like the BAFO-100c, use the half duplex version.)
* - For the full duplex model, the low bit of the version code says
* which side is which ("left/right").
* - For the half duplex type, a control/interrupt handshake settles
* the transfer direction. (That's disabled here, partially coded.)
* A control URB would block until other side writes an interrupt.
*
* Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
* and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>.
*/
// control msg write command
#define GENELINK_CONNECT_WRITE 0xF0
// interrupt pipe index
#define GENELINK_INTERRUPT_PIPE 0x03
// interrupt read buffer size
#define INTERRUPT_BUFSIZE 0x08
// interrupt pipe interval value
#define GENELINK_INTERRUPT_INTERVAL 0x10
// max transmit packet number per transmit
#define GL_MAX_TRANSMIT_PACKETS 32
// max packet length
#define GL_MAX_PACKET_LEN 1514
// max receive buffer size
#define GL_RCV_BUF_SIZE \
(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
struct gl_packet {
u32 packet_length;
char packet_data [1];
};
struct gl_header {
u32 packet_count;
struct gl_packet packets;
};
#ifdef GENELINK_ACK
// FIXME: this code is incomplete, not debugged; it doesn't
// handle interrupts correctly; it should use the generic
// status IRQ code (which didn't exist back in 2001).
struct gl_priv {
struct urb *irq_urb;
char irq_buf [INTERRUPT_BUFSIZE];
};
static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value)
{
int retval;
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
request,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
value,
0, // index
0, // data buffer
0, // size
USB_CTRL_SET_TIMEOUT);
return retval;
}
static void gl_interrupt_complete(struct urb *urb, struct pt_regs *regs)
{
int status = urb->status;
switch (status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
__FUNCTION__, urb->status);
}
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
err("%s - usb_submit_urb failed with result %d",
__FUNCTION__, status);
}
static int gl_interrupt_read(struct usbnet *dev)
{
struct gl_priv *priv = dev->priv_data;
int retval;
// issue usb interrupt read
if (priv && priv->irq_urb) {
// submit urb
if ((retval = usb_submit_urb(priv->irq_urb, GFP_KERNEL)) != 0)
dbg("gl_interrupt_read: submit fail - %X...", retval);
else
dbg("gl_interrupt_read: submit success...");
}
return 0;
}
// check whether another side is connected
static int genelink_check_connect(struct usbnet *dev)
{
int retval;
dbg("genelink_check_connect...");
// detect whether another side is connected
if ((retval = gl_control_write(dev, GENELINK_CONNECT_WRITE, 0)) != 0) {
dbg("%s: genelink_check_connect write fail - %X",
dev->net->name, retval);
return retval;
}
// usb interrupt read to ack another side
if ((retval = gl_interrupt_read(dev)) != 0) {
dbg("%s: genelink_check_connect read fail - %X",
dev->net->name, retval);
return retval;
}
dbg("%s: genelink_check_connect read success", dev->net->name);
return 0;
}
// allocate and initialize the private data for genelink
static int genelink_init(struct usbnet *dev)
{
struct gl_priv *priv;
// allocate the private data structure
if ((priv = kmalloc(sizeof *priv, GFP_KERNEL)) == 0) {
dbg("%s: cannot allocate private data per device",
dev->net->name);
return -ENOMEM;
}
// allocate irq urb
if ((priv->irq_urb = usb_alloc_urb(0, GFP_KERNEL)) == 0) {
dbg("%s: cannot allocate private irq urb per device",
dev->net->name);
kfree(priv);
return -ENOMEM;
}
// fill irq urb
usb_fill_int_urb(priv->irq_urb, dev->udev,
usb_rcvintpipe(dev->udev, GENELINK_INTERRUPT_PIPE),
priv->irq_buf, INTERRUPT_BUFSIZE,
gl_interrupt_complete, 0,
GENELINK_INTERRUPT_INTERVAL);
// set private data pointer
dev->priv_data = priv;
return 0;
}
// release the private data
static int genelink_free(struct usbnet *dev)
{
struct gl_priv *priv = dev->priv_data;
if (!priv)
return 0;
// FIXME: can't cancel here; it's synchronous, and
// should have happened earlier in any case (interrupt
// handling needs to be generic)
// cancel irq urb first
usb_kill_urb(priv->irq_urb);
// free irq urb
usb_free_urb(priv->irq_urb);
// free the private data structure
kfree(priv);
return 0;
}
#endif
static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
struct gl_header *header;
struct gl_packet *packet;
struct sk_buff *gl_skb;
u32 size;
header = (struct gl_header *) skb->data;
// get the packet count of the received skb
le32_to_cpus(&header->packet_count);
if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS)
|| (header->packet_count < 0)) {
dbg("genelink: invalid received packet count %d",
header->packet_count);
return 0;
}
// set the current packet pointer to the first packet
packet = &header->packets;
// decrement the length for the packet count size 4 bytes
skb_pull(skb, 4);
while (header->packet_count > 1) {
// get the packet length
size = le32_to_cpu(packet->packet_length);
// this may be a broken packet
if (size > GL_MAX_PACKET_LEN) {
dbg("genelink: invalid rx length %d", size);
return 0;
}
// allocate the skb for the individual packet
gl_skb = alloc_skb(size, GFP_ATOMIC);
if (gl_skb) {
// copy the packet data to the new skb
memcpy(skb_put(gl_skb, size),
packet->packet_data, size);
usbnet_skb_return(dev, gl_skb);
}
// advance to the next packet
packet = (struct gl_packet *)
&packet->packet_data [size];
header->packet_count--;
// shift the data pointer to the next gl_packet
skb_pull(skb, size + 4);
}
// skip the packet length field 4 bytes
skb_pull(skb, 4);
if (skb->len > GL_MAX_PACKET_LEN) {
dbg("genelink: invalid rx length %d", skb->len);
return 0;
}
return 1;
}
static struct sk_buff *
genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags)
{
int padlen;
int length = skb->len;
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
u32 *packet_count;
u32 *packet_len;
// FIXME: magic numbers, bleech
padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
if ((!skb_cloned(skb))
&& ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
skb->data = memmove(skb->head + (4 + 4*1),
skb->data, skb->len);
skb->tail = skb->data + skb->len;
}
} else {
struct sk_buff *skb2;
skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (!skb)
return NULL;
}
// attach the packet count to the header
packet_count = (u32 *) skb_push(skb, (4 + 4*1));
packet_len = packet_count + 1;
*packet_count = cpu_to_le32(1);
*packet_len = cpu_to_le32(length);
// add padding byte
if ((skb->len % dev->maxpacket) == 0)
skb_put(skb, 1);
return skb;
}
static int genelink_bind(struct usbnet *dev, struct usb_interface *intf)
{
dev->hard_mtu = GL_RCV_BUF_SIZE;
dev->net->hard_header_len += 4;
dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in);
dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out);
return 0;
}
static const struct driver_info genelink_info = {
.description = "Genesys GeneLink",
.flags = FLAG_FRAMING_GL | FLAG_NO_SETINT,
.bind = genelink_bind,
.rx_fixup = genelink_rx_fixup,
.tx_fixup = genelink_tx_fixup,
.in = 1, .out = 2,
#ifdef GENELINK_ACK
.check_connect =genelink_check_connect,
#endif
};
static const struct usb_device_id products [] = {
{
USB_DEVICE(0x05e3, 0x0502), // GL620USB-A
.driver_info = (unsigned long) &genelink_info,
},
/* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB
* that's half duplex, not currently supported
*/
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver gl620a_driver = {
.owner = THIS_MODULE,
.name = "gl620a",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init usbnet_init(void)
{
return usb_register(&gl620a_driver);
}
module_init(usbnet_init);
static void __exit usbnet_exit(void)
{
usb_deregister(&gl620a_driver);
}
module_exit(usbnet_exit);
MODULE_AUTHOR("Jiun-Jie Huang");
MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables");
MODULE_LICENSE("GPL");

View file

@ -787,7 +787,6 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth_usb_transmit_complete,
kaweth);
kaweth->end = 0;
kaweth->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
{

622
drivers/usb/net/net1080.c Normal file
View file

@ -0,0 +1,622 @@
/*
* Net1080 based USB host-to-host cables
* Copyright (C) 2000-2005 by David Brownell
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <asm/unaligned.h>
#include "usbnet.h"
/*
* Netchip 1080 driver ... http://www.netchip.com
* (Sept 2004: End-of-life announcement has been sent.)
* Used in (some) LapLink cables
*/
#define frame_errors data[1]
/*
* NetChip framing of ethernet packets, supporting additional error
* checks for links that may drop bulk packets from inside messages.
* Odd USB length == always short read for last usb packet.
* - nc_header
* - Ethernet header (14 bytes)
* - payload
* - (optional padding byte, if needed so length becomes odd)
* - nc_trailer
*
* This framing is to be avoided for non-NetChip devices.
*/
struct nc_header { // packed:
__le16 hdr_len; // sizeof nc_header (LE, all)
__le16 packet_len; // payload size (including ethhdr)
__le16 packet_id; // detects dropped packets
#define MIN_HEADER 6
// all else is optional, and must start with:
// __le16 vendorId; // from usb-if
// __le16 productId;
} __attribute__((__packed__));
#define PAD_BYTE ((unsigned char)0xAC)
struct nc_trailer {
__le16 packet_id;
} __attribute__((__packed__));
// packets may use FLAG_FRAMING_NC and optional pad
#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
+ sizeof (struct ethhdr) \
+ (mtu) \
+ 1 \
+ sizeof (struct nc_trailer))
#define MIN_FRAMED FRAMED_SIZE(0)
/* packets _could_ be up to 64KB... */
#define NC_MAX_PACKET 32767
/*
* Zero means no timeout; else, how long a 64 byte bulk packet may be queued
* before the hardware drops it. If that's done, the driver will need to
* frame network packets to guard against the dropped USB packets. The win32
* driver sets this for both sides of the link.
*/
#define NC_READ_TTL_MS ((u8)255) // ms
/*
* We ignore most registers and EEPROM contents.
*/
#define REG_USBCTL ((u8)0x04)
#define REG_TTL ((u8)0x10)
#define REG_STATUS ((u8)0x11)
/*
* Vendor specific requests to read/write data
*/
#define REQUEST_REGISTER ((u8)0x10)
#define REQUEST_EEPROM ((u8)0x11)
static int
nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr)
{
int status = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, regnum,
retval_ptr, sizeof *retval_ptr,
USB_CTRL_GET_TIMEOUT);
if (status > 0)
status = 0;
if (!status)
le16_to_cpus(retval_ptr);
return status;
}
static inline int
nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr)
{
return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr);
}
// no retval ... can become async, usable in_interrupt()
static void
nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value)
{
usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, regnum,
NULL, 0, // data is in setup packet
USB_CTRL_SET_TIMEOUT);
}
static inline void
nc_register_write(struct usbnet *dev, u8 regnum, u16 value)
{
nc_vendor_write(dev, REQUEST_REGISTER, regnum, value);
}
#if 0
static void nc_dump_registers(struct usbnet *dev)
{
u8 reg;
u16 *vp = kmalloc(sizeof (u16));
if (!vp) {
dbg("no memory?");
return;
}
dbg("%s registers:", dev->net->name);
for (reg = 0; reg < 0x20; reg++) {
int retval;
// reading some registers is trouble
if (reg >= 0x08 && reg <= 0xf)
continue;
if (reg >= 0x12 && reg <= 0x1e)
continue;
retval = nc_register_read(dev, reg, vp);
if (retval < 0)
dbg("%s reg [0x%x] ==> error %d",
dev->net->name, reg, retval);
else
dbg("%s reg [0x%x] = 0x%x",
dev->net->name, reg, *vp);
}
kfree(vp);
}
#endif
/*-------------------------------------------------------------------------*/
/*
* Control register
*/
#define USBCTL_WRITABLE_MASK 0x1f0f
// bits 15-13 reserved, r/o
#define USBCTL_ENABLE_LANG (1 << 12)
#define USBCTL_ENABLE_MFGR (1 << 11)
#define USBCTL_ENABLE_PROD (1 << 10)
#define USBCTL_ENABLE_SERIAL (1 << 9)
#define USBCTL_ENABLE_DEFAULTS (1 << 8)
// bits 7-4 reserved, r/o
#define USBCTL_FLUSH_OTHER (1 << 3)
#define USBCTL_FLUSH_THIS (1 << 2)
#define USBCTL_DISCONN_OTHER (1 << 1)
#define USBCTL_DISCONN_THIS (1 << 0)
static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl)
{
if (!netif_msg_link(dev))
return;
devdbg(dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;"
" this%s%s;"
" other%s%s; r/o 0x%x",
dev->udev->bus->bus_name, dev->udev->devpath,
usbctl,
(usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
(usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
(usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
(usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
(usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
(usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
(usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
(usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
(usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
usbctl & ~USBCTL_WRITABLE_MASK
);
}
/*-------------------------------------------------------------------------*/
/*
* Status register
*/
#define STATUS_PORT_A (1 << 15)
#define STATUS_CONN_OTHER (1 << 14)
#define STATUS_SUSPEND_OTHER (1 << 13)
#define STATUS_MAILBOX_OTHER (1 << 12)
#define STATUS_PACKETS_OTHER(n) (((n) >> 8) && 0x03)
#define STATUS_CONN_THIS (1 << 6)
#define STATUS_SUSPEND_THIS (1 << 5)
#define STATUS_MAILBOX_THIS (1 << 4)
#define STATUS_PACKETS_THIS(n) (((n) >> 0) && 0x03)
#define STATUS_UNSPEC_MASK 0x0c8c
#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK))
static inline void nc_dump_status(struct usbnet *dev, u16 status)
{
if (!netif_msg_link(dev))
return;
devdbg(dev, "net1080 %s-%s status 0x%x:"
" this (%c) PKT=%d%s%s%s;"
" other PKT=%d%s%s%s; unspec 0x%x",
dev->udev->bus->bus_name, dev->udev->devpath,
status,
// XXX the packet counts don't seem right
// (1 at reset, not 0); maybe UNSPEC too
(status & STATUS_PORT_A) ? 'A' : 'B',
STATUS_PACKETS_THIS(status),
(status & STATUS_CONN_THIS) ? " CON" : "",
(status & STATUS_SUSPEND_THIS) ? " SUS" : "",
(status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
STATUS_PACKETS_OTHER(status),
(status & STATUS_CONN_OTHER) ? " CON" : "",
(status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
(status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
status & STATUS_UNSPEC_MASK
);
}
/*-------------------------------------------------------------------------*/
/*
* TTL register
*/
#define TTL_THIS(ttl) (0x00ff & ttl)
#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8))
#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this))))
static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl)
{
if (netif_msg_link(dev))
devdbg(dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d",
dev->udev->bus->bus_name, dev->udev->devpath,
ttl, TTL_THIS(ttl), TTL_OTHER(ttl));
}
/*-------------------------------------------------------------------------*/
static int net1080_reset(struct usbnet *dev)
{
u16 usbctl, status, ttl;
u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL);
int retval;
if (!vp)
return -ENOMEM;
// nc_dump_registers(dev);
if ((retval = nc_register_read(dev, REG_STATUS, vp)) < 0) {
dbg("can't read %s-%s status: %d",
dev->udev->bus->bus_name, dev->udev->devpath, retval);
goto done;
}
status = *vp;
nc_dump_status(dev, status);
if ((retval = nc_register_read(dev, REG_USBCTL, vp)) < 0) {
dbg("can't read USBCTL, %d", retval);
goto done;
}
usbctl = *vp;
nc_dump_usbctl(dev, usbctl);
nc_register_write(dev, REG_USBCTL,
USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);
if ((retval = nc_register_read(dev, REG_TTL, vp)) < 0) {
dbg("can't read TTL, %d", retval);
goto done;
}
ttl = *vp;
// nc_dump_ttl(dev, ttl);
nc_register_write(dev, REG_TTL,
MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) );
dbg("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS);
if (netif_msg_link(dev))
devinfo(dev, "port %c, peer %sconnected",
(status & STATUS_PORT_A) ? 'A' : 'B',
(status & STATUS_CONN_OTHER) ? "" : "dis"
);
retval = 0;
done:
kfree(vp);
return retval;
}
static int net1080_check_connect(struct usbnet *dev)
{
int retval;
u16 status;
u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL);
if (!vp)
return -ENOMEM;
retval = nc_register_read(dev, REG_STATUS, vp);
status = *vp;
kfree(vp);
if (retval != 0) {
dbg("%s net1080_check_conn read - %d", dev->net->name, retval);
return retval;
}
if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)
return -ENOLINK;
return 0;
}
static void nc_flush_complete(struct urb *urb, struct pt_regs *regs)
{
kfree(urb->context);
usb_free_urb(urb);
}
static void nc_ensure_sync(struct usbnet *dev)
{
dev->frame_errors++;
if (dev->frame_errors > 5) {
struct urb *urb;
struct usb_ctrlrequest *req;
int status;
/* Send a flush */
urb = usb_alloc_urb(0, SLAB_ATOMIC);
if (!urb)
return;
req = kmalloc(sizeof *req, GFP_ATOMIC);
if (!req) {
usb_free_urb(urb);
return;
}
req->bRequestType = USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE;
req->bRequest = REQUEST_REGISTER;
req->wValue = cpu_to_le16(USBCTL_FLUSH_THIS
| USBCTL_FLUSH_OTHER);
req->wIndex = cpu_to_le16(REG_USBCTL);
req->wLength = cpu_to_le16(0);
/* queue an async control request, we don't need
* to do anything when it finishes except clean up.
*/
usb_fill_control_urb(urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0),
(unsigned char *) req,
NULL, 0,
nc_flush_complete, req);
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
kfree(req);
usb_free_urb(urb);
return;
}
if (netif_msg_rx_err(dev))
devdbg(dev, "flush net1080; too many framing errors");
dev->frame_errors = 0;
}
}
static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
struct nc_header *header;
struct nc_trailer *trailer;
u16 hdr_len, packet_len;
if (!(skb->len & 0x01)) {
#ifdef DEBUG
struct net_device *net = dev->net;
dbg("rx framesize %d range %d..%d mtu %d", skb->len,
net->hard_header_len, dev->hard_mtu, net->mtu);
#endif
dev->stats.rx_frame_errors++;
nc_ensure_sync(dev);
return 0;
}
header = (struct nc_header *) skb->data;
hdr_len = le16_to_cpup(&header->hdr_len);
packet_len = le16_to_cpup(&header->packet_len);
if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) {
dev->stats.rx_frame_errors++;
dbg("packet too big, %d", packet_len);
nc_ensure_sync(dev);
return 0;
} else if (hdr_len < MIN_HEADER) {
dev->stats.rx_frame_errors++;
dbg("header too short, %d", hdr_len);
nc_ensure_sync(dev);
return 0;
} else if (hdr_len > MIN_HEADER) {
// out of band data for us?
dbg("header OOB, %d bytes", hdr_len - MIN_HEADER);
nc_ensure_sync(dev);
// switch (vendor/product ids) { ... }
}
skb_pull(skb, hdr_len);
trailer = (struct nc_trailer *)
(skb->data + skb->len - sizeof *trailer);
skb_trim(skb, skb->len - sizeof *trailer);
if ((packet_len & 0x01) == 0) {
if (skb->data [packet_len] != PAD_BYTE) {
dev->stats.rx_frame_errors++;
dbg("bad pad");
return 0;
}
skb_trim(skb, skb->len - 1);
}
if (skb->len != packet_len) {
dev->stats.rx_frame_errors++;
dbg("bad packet len %d (expected %d)",
skb->len, packet_len);
nc_ensure_sync(dev);
return 0;
}
if (header->packet_id != get_unaligned(&trailer->packet_id)) {
dev->stats.rx_fifo_errors++;
dbg("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
le16_to_cpu(header->packet_id),
le16_to_cpu(trailer->packet_id));
return 0;
}
#if 0
devdbg(dev, "frame <rx h %d p %d id %d", header->hdr_len,
header->packet_len, header->packet_id);
#endif
dev->frame_errors = 0;
return 1;
}
static struct sk_buff *
net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags)
{
int padlen;
struct sk_buff *skb2;
struct nc_header *header = NULL;
struct nc_trailer *trailer = NULL;
int len = skb->len;
padlen = ((len + sizeof (struct nc_header)
+ sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
if (!skb_cloned(skb)) {
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
if ((padlen + sizeof (struct nc_trailer)) <= tailroom
&& sizeof (struct nc_header) <= headroom)
/* There's enough head and tail room */
goto encapsulate;
if ((sizeof (struct nc_header) + padlen
+ sizeof (struct nc_trailer)) <
(headroom + tailroom)) {
/* There's enough total room, so just readjust */
skb->data = memmove(skb->head
+ sizeof (struct nc_header),
skb->data, skb->len);
skb->tail = skb->data + len;
goto encapsulate;
}
}
/* Create a new skb to use with the correct size */
skb2 = skb_copy_expand(skb,
sizeof (struct nc_header),
sizeof (struct nc_trailer) + padlen,
flags);
dev_kfree_skb_any(skb);
if (!skb2)
return skb2;
skb = skb2;
encapsulate:
/* header first */
header = (struct nc_header *) skb_push(skb, sizeof *header);
header->hdr_len = cpu_to_le16(sizeof (*header));
header->packet_len = cpu_to_le16(len);
header->packet_id = cpu_to_le16((u16)dev->xid++);
/* maybe pad; then trailer */
if (!((skb->len + sizeof *trailer) & 0x01))
*skb_put(skb, 1) = PAD_BYTE;
trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer);
put_unaligned(header->packet_id, &trailer->packet_id);
#if 0
devdbg(dev, "frame >tx h %d p %d id %d",
header->hdr_len, header->packet_len,
header->packet_id);
#endif
return skb;
}
static int net1080_bind(struct usbnet *dev, struct usb_interface *intf)
{
unsigned extra = sizeof (struct nc_header)
+ 1
+ sizeof (struct nc_trailer);
dev->net->hard_header_len += extra;
dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
dev->hard_mtu = NC_MAX_PACKET;
return usbnet_get_endpoints (dev, intf);
}
static const struct driver_info net1080_info = {
.description = "NetChip TurboCONNECT",
.flags = FLAG_FRAMING_NC,
.bind = net1080_bind,
.reset = net1080_reset,
.check_connect = net1080_check_connect,
.rx_fixup = net1080_rx_fixup,
.tx_fixup = net1080_tx_fixup,
};
static const struct usb_device_id products [] = {
{
USB_DEVICE(0x0525, 0x1080), // NetChip ref design
.driver_info = (unsigned long) &net1080_info,
}, {
USB_DEVICE(0x06D0, 0x0622), // Laplink Gold
.driver_info = (unsigned long) &net1080_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver net1080_driver = {
.owner = THIS_MODULE,
.name = "net1080",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init net1080_init(void)
{
return usb_register(&net1080_driver);
}
module_init(net1080_init);
static void __exit net1080_exit(void)
{
usb_deregister(&net1080_driver);
}
module_exit(net1080_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links");
MODULE_LICENSE("GPL");

View file

@ -825,7 +825,6 @@ static void pegasus_tx_timeout(struct net_device *net)
pegasus_t *pegasus = netdev_priv(net);
if (netif_msg_timer(pegasus))
printk(KERN_WARNING "%s: tx timeout\n", net->name);
pegasus->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_unlink_urb(pegasus->tx_urb);
pegasus->stats.tx_errors++;
}

156
drivers/usb/net/plusb.c Normal file
View file

@ -0,0 +1,156 @@
/*
* PL-2301/2302 USB host-to-host link cables
* Copyright (C) 2000-2005 by David Brownell
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include "usbnet.h"
/*
* Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com
*
* The protocol and handshaking used here should be bug-compatible
* with the Linux 2.2 "plusb" driver, by Deti Fliegl.
*
* HEADS UP: this handshaking isn't all that robust. This driver
* gets confused easily if you unplug one end of the cable then
* try to connect it again; you'll need to restart both ends. The
* "naplink" software (used by some PlayStation/2 deveopers) does
* the handshaking much better! Also, sometimes this hardware
* seems to get wedged under load. Prolific docs are weak, and
* don't identify differences between PL2301 and PL2302, much less
* anything to explain the different PL2302 versions observed.
*/
/*
* Bits 0-4 can be used for software handshaking; they're set from
* one end, cleared from the other, "read" with the interrupt byte.
*/
#define PL_S_EN (1<<7) /* (feature only) suspend enable */
/* reserved bit -- rx ready (6) ? */
#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */
#define PL_RESET_OUT (1<<4) /* reset output pipe */
#define PL_RESET_IN (1<<3) /* reset input pipe */
#define PL_TX_C (1<<2) /* transmission complete */
#define PL_TX_REQ (1<<1) /* transmission received */
#define PL_PEER_E (1<<0) /* peer exists */
static inline int
pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index)
{
return usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
val, index,
NULL, 0,
USB_CTRL_GET_TIMEOUT);
}
static inline int
pl_clear_QuickLink_features(struct usbnet *dev, int val)
{
return pl_vendor_req(dev, 1, (u8) val, 0);
}
static inline int
pl_set_QuickLink_features(struct usbnet *dev, int val)
{
return pl_vendor_req(dev, 3, (u8) val, 0);
}
static int pl_reset(struct usbnet *dev)
{
/* some units seem to need this reset, others reject it utterly.
* FIXME be more like "naplink" or windows drivers.
*/
(void) pl_set_QuickLink_features(dev,
PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
return 0;
}
static const struct driver_info prolific_info = {
.description = "Prolific PL-2301/PL-2302",
.flags = FLAG_NO_SETINT,
/* some PL-2302 versions seem to fail usb_set_interface() */
.reset = pl_reset,
};
/*-------------------------------------------------------------------------*/
/*
* Proilific's name won't normally be on the cables, and
* may not be on the device.
*/
static const struct usb_device_id products [] = {
{
USB_DEVICE(0x067b, 0x0000), // PL-2301
.driver_info = (unsigned long) &prolific_info,
}, {
USB_DEVICE(0x067b, 0x0001), // PL-2302
.driver_info = (unsigned long) &prolific_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver plusb_driver = {
.owner = THIS_MODULE,
.name = "plusb",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init plusb_init(void)
{
return usb_register(&plusb_driver);
}
module_init(plusb_init);
static void __exit plusb_exit(void)
{
usb_deregister(&plusb_driver);
}
module_exit(plusb_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,615 @@
/*
* Host Side support for RNDIS Networking Links
* Copyright (C) 2005 by David Brownell
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb_cdc.h>
#include "usbnet.h"
/*
* RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of
* course ACM was intended for modems, not Ethernet links! USB's standard
* for Ethernet links is "CDC Ethernet", which is significantly simpler.
*/
/*
* CONTROL uses CDC "encapsulated commands" with funky notifications.
* - control-out: SEND_ENCAPSULATED
* - interrupt-in: RESPONSE_AVAILABLE
* - control-in: GET_ENCAPSULATED
*
* We'll try to ignore the RESPONSE_AVAILABLE notifications.
*/
struct rndis_msg_hdr {
__le32 msg_type; /* RNDIS_MSG_* */
__le32 msg_len;
// followed by data that varies between messages
__le32 request_id;
__le32 status;
// ... and more
} __attribute__ ((packed));
/* RNDIS defines this (absurdly huge) control timeout */
#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000)
#define ccpu2 __constant_cpu_to_le32
#define RNDIS_MSG_COMPLETION ccpu2(0x80000000)
/* codes for "msg_type" field of rndis messages;
* only the data channel uses packet messages (maybe batched);
* everything else goes on the control channel.
*/
#define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */
#define RNDIS_MSG_INIT ccpu2(0x00000002)
#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_HALT ccpu2(0x00000003)
#define RNDIS_MSG_QUERY ccpu2(0x00000004)
#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_SET ccpu2(0x00000005)
#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_RESET ccpu2(0x00000006)
#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_INDICATE ccpu2(0x00000007)
#define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008)
#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
/* codes for "status" field of completion messages */
#define RNDIS_STATUS_SUCCESS ccpu2(0x00000000)
#define RNDIS_STATUS_FAILURE ccpu2(0xc0000001)
#define RNDIS_STATUS_INVALID_DATA ccpu2(0xc0010015)
#define RNDIS_STATUS_NOT_SUPPORTED ccpu2(0xc00000bb)
#define RNDIS_STATUS_MEDIA_CONNECT ccpu2(0x4001000b)
#define RNDIS_STATUS_MEDIA_DISCONNECT ccpu2(0x4001000c)
struct rndis_data_hdr {
__le32 msg_type; /* RNDIS_MSG_PACKET */
__le32 msg_len; // rndis_data_hdr + data_len + pad
__le32 data_offset; // 36 -- right after header
__le32 data_len; // ... real packet size
__le32 oob_data_offset; // zero
__le32 oob_data_len; // zero
__le32 num_oob; // zero
__le32 packet_data_offset; // zero
__le32 packet_data_len; // zero
__le32 vc_handle; // zero
__le32 reserved; // zero
} __attribute__ ((packed));
struct rndis_init { /* OUT */
// header and:
__le32 msg_type; /* RNDIS_MSG_INIT */
__le32 msg_len; // 24
__le32 request_id;
__le32 major_version; // of rndis (1.0)
__le32 minor_version;
__le32 max_transfer_size;
} __attribute__ ((packed));
struct rndis_init_c { /* IN */
// header and:
__le32 msg_type; /* RNDIS_MSG_INIT_C */
__le32 msg_len;
__le32 request_id;
__le32 status;
__le32 major_version; // of rndis (1.0)
__le32 minor_version;
__le32 device_flags;
__le32 medium; // zero == 802.3
__le32 max_packets_per_message;
__le32 max_transfer_size;
__le32 packet_alignment; // max 7; (1<<n) bytes
__le32 af_list_offset; // zero
__le32 af_list_size; // zero
} __attribute__ ((packed));
struct rndis_halt { /* OUT (no reply) */
// header and:
__le32 msg_type; /* RNDIS_MSG_HALT */
__le32 msg_len;
__le32 request_id;
} __attribute__ ((packed));
struct rndis_query { /* OUT */
// header and:
__le32 msg_type; /* RNDIS_MSG_QUERY */
__le32 msg_len;
__le32 request_id;
__le32 oid;
__le32 len;
__le32 offset;
/*?*/ __le32 handle; // zero
} __attribute__ ((packed));
struct rndis_query_c { /* IN */
// header and:
__le32 msg_type; /* RNDIS_MSG_QUERY_C */
__le32 msg_len;
__le32 request_id;
__le32 status;
__le32 len;
__le32 offset;
} __attribute__ ((packed));
struct rndis_set { /* OUT */
// header and:
__le32 msg_type; /* RNDIS_MSG_SET */
__le32 msg_len;
__le32 request_id;
__le32 oid;
__le32 len;
__le32 offset;
/*?*/ __le32 handle; // zero
} __attribute__ ((packed));
struct rndis_set_c { /* IN */
// header and:
__le32 msg_type; /* RNDIS_MSG_SET_C */
__le32 msg_len;
__le32 request_id;
__le32 status;
} __attribute__ ((packed));
struct rndis_reset { /* IN */
// header and:
__le32 msg_type; /* RNDIS_MSG_RESET */
__le32 msg_len;
__le32 reserved;
} __attribute__ ((packed));
struct rndis_reset_c { /* OUT */
// header and:
__le32 msg_type; /* RNDIS_MSG_RESET_C */
__le32 msg_len;
__le32 status;
__le32 addressing_lost;
} __attribute__ ((packed));
struct rndis_indicate { /* IN (unrequested) */
// header and:
__le32 msg_type; /* RNDIS_MSG_INDICATE */
__le32 msg_len;
__le32 status;
__le32 length;
__le32 offset;
/**/ __le32 diag_status;
__le32 error_offset;
/**/ __le32 message;
} __attribute__ ((packed));
struct rndis_keepalive { /* OUT (optionally IN) */
// header and:
__le32 msg_type; /* RNDIS_MSG_KEEPALIVE */
__le32 msg_len;
__le32 request_id;
} __attribute__ ((packed));
struct rndis_keepalive_c { /* IN (optionally OUT) */
// header and:
__le32 msg_type; /* RNDIS_MSG_KEEPALIVE_C */
__le32 msg_len;
__le32 request_id;
__le32 status;
} __attribute__ ((packed));
/* NOTE: about 30 OIDs are "mandatory" for peripherals to support ... and
* there are gobs more that may optionally be supported. We'll avoid as much
* of that mess as possible.
*/
#define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101)
#define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e)
/*
* RNDIS notifications from device: command completion; "reverse"
* keepalives; etc
*/
static void rndis_status(struct usbnet *dev, struct urb *urb)
{
devdbg(dev, "rndis status urb, len %d stat %d",
urb->actual_length, urb->status);
// FIXME for keepalives, respond immediately (asynchronously)
// if not an RNDIS status, do like cdc_status(dev,urb) does
}
/*
* RPC done RNDIS-style. Caller guarantees:
* - message is properly byteswapped
* - there's no other request pending
* - buf can hold up to 1KB response (required by RNDIS spec)
* On return, the first few entries are already byteswapped.
*
* Call context is likely probe(), before interface name is known,
* which is why we won't try to use it in the diagnostics.
*/
static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
{
struct cdc_state *info = (void *) &dev->data;
int retval;
unsigned count;
__le32 rsp;
u32 xid = 0, msg_len, request_id;
/* REVISIT when this gets called from contexts other than probe() or
* disconnect(): either serialize, or dispatch responses on xid
*/
/* Issue the request; don't bother byteswapping our xid */
if (likely(buf->msg_type != RNDIS_MSG_HALT
&& buf->msg_type != RNDIS_MSG_RESET)) {
xid = dev->xid++;
if (!xid)
xid = dev->xid++;
buf->request_id = (__force __le32) xid;
}
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, info->u->bMasterInterface0,
buf, le32_to_cpu(buf->msg_len),
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0 || xid == 0))
return retval;
// FIXME Seems like some devices discard responses when
// we time out and cancel our "get response" requests...
// so, this is fragile. Probably need to poll for status.
/* ignore status endpoint, just poll the control channel;
* the request probably completed immediately
*/
rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
for (count = 0; count < 10; count++) {
memset(buf, 0, 1024);
retval = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
USB_CDC_GET_ENCAPSULATED_RESPONSE,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, info->u->bMasterInterface0,
buf, 1024,
RNDIS_CONTROL_TIMEOUT_MS);
if (likely(retval >= 8)) {
msg_len = le32_to_cpu(buf->msg_len);
request_id = (__force u32) buf->request_id;
if (likely(buf->msg_type == rsp)) {
if (likely(request_id == xid)) {
if (unlikely(rsp == RNDIS_MSG_RESET_C))
return 0;
if (likely(RNDIS_STATUS_SUCCESS
== buf->status))
return 0;
dev_dbg(&info->control->dev,
"rndis reply status %08x\n",
le32_to_cpu(buf->status));
return -EL3RST;
}
dev_dbg(&info->control->dev,
"rndis reply id %d expected %d\n",
request_id, xid);
/* then likely retry */
} else switch (buf->msg_type) {
case RNDIS_MSG_INDICATE: { /* fault */
// struct rndis_indicate *msg = (void *)buf;
dev_info(&info->control->dev,
"rndis fault indication\n");
}
break;
case RNDIS_MSG_KEEPALIVE: { /* ping */
struct rndis_keepalive_c *msg = (void *)buf;
msg->msg_type = RNDIS_MSG_KEEPALIVE_C;
msg->msg_len = ccpu2(sizeof *msg);
msg->status = RNDIS_STATUS_SUCCESS;
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, info->u->bMasterInterface0,
msg, sizeof *msg,
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0))
dev_dbg(&info->control->dev,
"rndis keepalive err %d\n",
retval);
}
break;
default:
dev_dbg(&info->control->dev,
"unexpected rndis msg %08x len %d\n",
le32_to_cpu(buf->msg_type), msg_len);
}
} else {
/* device probably issued a protocol stall; ignore */
dev_dbg(&info->control->dev,
"rndis response error, code %d\n", retval);
}
msleep(2);
}
dev_dbg(&info->control->dev, "rndis response timeout\n");
return -ETIMEDOUT;
}
static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
{
int retval;
struct net_device *net = dev->net;
union {
void *buf;
struct rndis_msg_hdr *header;
struct rndis_init *init;
struct rndis_init_c *init_c;
struct rndis_query *get;
struct rndis_query_c *get_c;
struct rndis_set *set;
struct rndis_set_c *set_c;
} u;
u32 tmp;
/* we can't rely on i/o from stack working, or stack allocation */
u.buf = kmalloc(1024, GFP_KERNEL);
if (!u.buf)
return -ENOMEM;
retval = usbnet_generic_cdc_bind(dev, intf);
if (retval < 0)
goto done;
net->hard_header_len += sizeof (struct rndis_data_hdr);
/* initialize; max transfer is 16KB at full speed */
u.init->msg_type = RNDIS_MSG_INIT;
u.init->msg_len = ccpu2(sizeof *u.init);
u.init->major_version = ccpu2(1);
u.init->minor_version = ccpu2(0);
u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
/* it might not even be an RNDIS device!! */
dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
fail:
usb_driver_release_interface(driver_of(intf),
((struct cdc_state *)&(dev->data))->data);
goto done;
}
dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
/* REVISIT: peripheral "alignment" request is ignored ... */
dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
1 << le32_to_cpu(u.init_c->packet_alignment));
/* get designated host ethernet address */
memset(u.get, 0, sizeof *u.get);
u.get->msg_type = RNDIS_MSG_QUERY;
u.get->msg_len = ccpu2(sizeof *u.get);
u.get->oid = OID_802_3_PERMANENT_ADDRESS;
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
goto fail;
}
tmp = le32_to_cpu(u.get_c->offset);
if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
|| u.get_c->len != ccpu2(ETH_ALEN))) {
dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
tmp, le32_to_cpu(u.get_c->len));
retval = -EDOM;
goto fail;
}
memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN);
/* set a nonzero filter to enable data transfers */
memset(u.set, 0, sizeof *u.set);
u.set->msg_type = RNDIS_MSG_SET;
u.set->msg_len = ccpu2(4 + sizeof *u.set);
u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
u.set->len = ccpu2(4);
u.set->offset = ccpu2((sizeof *u.set) - 8);
*(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
goto fail;
}
retval = 0;
done:
kfree(u.buf);
return retval;
}
static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
{
struct rndis_halt *halt;
/* try to clear any rndis state/activity (no i/o from stack!) */
halt = kcalloc(1, sizeof *halt, SLAB_KERNEL);
if (halt) {
halt->msg_type = RNDIS_MSG_HALT;
halt->msg_len = ccpu2(sizeof *halt);
(void) rndis_command(dev, (void *)halt);
kfree(halt);
}
return usbnet_cdc_unbind(dev, intf);
}
/*
* DATA -- host must not write zlps
*/
static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
/* peripheral may have batched packets to us... */
while (likely(skb->len)) {
struct rndis_data_hdr *hdr = (void *)skb->data;
struct sk_buff *skb2;
u32 msg_len, data_offset, data_len;
msg_len = le32_to_cpu(hdr->msg_len);
data_offset = le32_to_cpu(hdr->data_offset);
data_len = le32_to_cpu(hdr->data_len);
/* don't choke if we see oob, per-packet data, etc */
if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET
|| skb->len < msg_len
|| (data_offset + data_len + 8) > msg_len)) {
dev->stats.rx_frame_errors++;
devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d",
le32_to_cpu(hdr->msg_type),
msg_len, data_offset, data_len, skb->len);
return 0;
}
skb_pull(skb, 8 + data_offset);
/* at most one packet left? */
if (likely((data_len - skb->len) <= sizeof *hdr)) {
skb_trim(skb, data_len);
break;
}
/* try to return all the packets in the batch */
skb2 = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!skb2))
break;
skb_pull(skb, msg_len - sizeof *hdr);
skb_trim(skb2, data_len);
usbnet_skb_return(dev, skb2);
}
/* caller will usbnet_skb_return the remaining packet */
return 1;
}
static struct sk_buff *
rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags)
{
struct rndis_data_hdr *hdr;
struct sk_buff *skb2;
unsigned len = skb->len;
if (likely(!skb_cloned(skb))) {
int room = skb_headroom(skb);
/* enough head room as-is? */
if (unlikely((sizeof *hdr) <= room))
goto fill;
/* enough room, but needs to be readjusted? */
room += skb_tailroom(skb);
if (likely((sizeof *hdr) <= room)) {
skb->data = memmove(skb->head + sizeof *hdr,
skb->data, len);
skb->tail = skb->data + len;
goto fill;
}
}
/* create a new skb, with the correct size (and tailpad) */
skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags);
dev_kfree_skb_any(skb);
if (unlikely(!skb2))
return skb2;
skb = skb2;
/* fill out the RNDIS header. we won't bother trying to batch
* packets; Linux minimizes wasted bandwidth through tx queues.
*/
fill:
hdr = (void *) __skb_push(skb, sizeof *hdr);
memset(hdr, 0, sizeof *hdr);
hdr->msg_type = RNDIS_MSG_PACKET;
hdr->msg_len = cpu_to_le32(skb->len);
hdr->data_offset = ccpu2(sizeof(*hdr) - 8);
hdr->data_len = cpu_to_le32(len);
/* FIXME make the last packet always be short ... */
return skb;
}
static const struct driver_info rndis_info = {
.description = "RNDIS device",
.flags = FLAG_ETHER | FLAG_FRAMING_RN,
.bind = rndis_bind,
.unbind = rndis_unbind,
.status = rndis_status,
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
};
#undef ccpu2
/*-------------------------------------------------------------------------*/
static const struct usb_device_id products [] = {
{
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver rndis_driver = {
.owner = THIS_MODULE,
.name = "rndis_host",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init rndis_init(void)
{
return usb_register(&rndis_driver);
}
module_init(rndis_init);
static void __exit rndis_exit(void)
{
usb_deregister(&rndis_driver);
}
module_exit(rndis_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("USB Host side RNDIS driver");
MODULE_LICENSE("GPL");

View file

@ -653,7 +653,6 @@ static void rtl8150_tx_timeout(struct net_device *netdev)
{
rtl8150_t *dev = netdev_priv(netdev);
warn("%s: Tx timeout.", netdev->name);
dev->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_unlink_urb(dev->tx_urb);
dev->stats.tx_errors++;
}

File diff suppressed because it is too large Load diff

193
drivers/usb/net/usbnet.h Normal file
View file

@ -0,0 +1,193 @@
/*
* USB Networking Link Interface
*
* Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net>
* Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __USBNET_H
#define __USBNET_H
/* interface from usbnet core to each USB networking link we handle */
struct usbnet {
/* housekeeping */
struct usb_device *udev;
struct driver_info *driver_info;
wait_queue_head_t *wait;
/* i/o info: pipes etc */
unsigned in, out;
struct usb_host_endpoint *status;
unsigned maxpacket;
struct timer_list delay;
/* protocol/interface state */
struct net_device *net;
struct net_device_stats stats;
int msg_enable;
unsigned long data [5];
u32 xid;
u32 hard_mtu; /* count any extra framing */
size_t rx_urb_size; /* size for rx urbs */
struct mii_if_info mii;
/* various kinds of pending driver work */
struct sk_buff_head rxq;
struct sk_buff_head txq;
struct sk_buff_head done;
struct urb *interrupt;
struct tasklet_struct bh;
struct work_struct kevent;
unsigned long flags;
# define EVENT_TX_HALT 0
# define EVENT_RX_HALT 1
# define EVENT_RX_MEMORY 2
# define EVENT_STS_SPLIT 3
# define EVENT_LINK_RESET 4
};
static inline struct usb_driver *driver_of(struct usb_interface *intf)
{
return to_usb_driver(intf->dev.driver);
}
/* interface from the device/framing level "minidriver" to core */
struct driver_info {
char *description;
int flags;
/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */
#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */
#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */
#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
/* init device ... can sleep, or cause probe() failure */
int (*bind)(struct usbnet *, struct usb_interface *);
/* cleanup device ... can sleep, but can't fail */
void (*unbind)(struct usbnet *, struct usb_interface *);
/* reset device ... can sleep */
int (*reset)(struct usbnet *);
/* see if peer is connected ... can sleep */
int (*check_connect)(struct usbnet *);
/* for status polling */
void (*status)(struct usbnet *, struct urb *);
/* link reset handling, called from defer_kevent */
int (*link_reset)(struct usbnet *);
/* fixup rx packet (strip framing) */
int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
/* fixup tx packet (add framing) */
struct sk_buff *(*tx_fixup)(struct usbnet *dev,
struct sk_buff *skb, unsigned flags);
/* for new devices, use the descriptor-reading code instead */
int in; /* rx endpoint */
int out; /* tx endpoint */
unsigned long data; /* Misc driver specific data */
};
/* Minidrivers are just drivers using the "usbnet" core as a powerful
* network-specific subroutine library ... that happens to do pretty
* much everything except custom framing and chip-specific stuff.
*/
extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *);
extern int usbnet_suspend (struct usb_interface *, pm_message_t );
extern int usbnet_resume (struct usb_interface *);
extern void usbnet_disconnect(struct usb_interface *);
/* Drivers that reuse some of the standard USB CDC infrastructure
* (notably, using multiple interfaces according to the the CDC
* union descriptor) get some helper code.
*/
struct cdc_state {
struct usb_cdc_header_desc *header;
struct usb_cdc_union_desc *u;
struct usb_cdc_ether_desc *ether;
struct usb_interface *control;
struct usb_interface *data;
};
extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *);
extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *);
/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
|USB_CDC_PACKET_TYPE_PROMISCUOUS \
|USB_CDC_PACKET_TYPE_DIRECTED)
/* we record the state for each of our queued skbs */
enum skb_state {
illegal = 0,
tx_start, tx_done,
rx_start, rx_done, rx_cleanup
};
struct skb_data { /* skb->cb is one of these */
struct urb *urb;
struct usbnet *dev;
enum skb_state state;
size_t length;
};
extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
extern void usbnet_defer_kevent (struct usbnet *, int);
extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
extern u32 usbnet_get_msglevel (struct net_device *);
extern void usbnet_set_msglevel (struct net_device *, u32);
extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
/* messaging support includes the interface name, so it must not be
* used before it has one ... notably, in minidriver bind() calls.
*/
#ifdef DEBUG
#define devdbg(usbnet, fmt, arg...) \
printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
#else
#define devdbg(usbnet, fmt, arg...) do {} while(0)
#endif
#define deverr(usbnet, fmt, arg...) \
printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
#define devwarn(usbnet, fmt, arg...) \
printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
#define devinfo(usbnet, fmt, arg...) \
printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
#endif /* __USBNET_H */

386
drivers/usb/net/zaurus.c Normal file
View file

@ -0,0 +1,386 @@
/*
* Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2002-2005 by David Brownell
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/crc32.h>
#include <linux/usb.h>
#include <linux/usb_cdc.h>
#include "usbnet.h"
/*
* All known Zaurii lie about their standards conformance. At least
* the earliest SA-1100 models lie by saying they support CDC Ethernet.
* Some later models (especially PXA-25x and PXA-27x based ones) lie
* and say they support CDC MDLM (for access to cell phone modems).
*
* There are non-Zaurus products that use these same protocols too.
*
* The annoying thing is that at the same time Sharp was developing
* that annoying standards-breaking software, the Linux community had
* a simple "CDC Subset" working reliably on the same SA-1100 hardware.
* That is, the same functionality but not violating standards.
*
* The CDC Ethernet nonconformance points are troublesome to hosts
* with a true CDC Ethernet implementation:
* - Framing appends a CRC, which the spec says drivers "must not" do;
* - Transfers data in altsetting zero, instead of altsetting 1;
* - All these peripherals use the same ethernet address.
*
* The CDC MDLM nonconformance is less immediately troublesome, since all
* MDLM implementations are quasi-proprietary anyway.
*/
static struct sk_buff *
zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags)
{
int padlen;
struct sk_buff *skb2;
padlen = 2;
if (!skb_cloned(skb)) {
int tailroom = skb_tailroom(skb);
if ((padlen + 4) <= tailroom)
goto done;
}
skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (skb) {
u32 fcs;
done:
fcs = crc32_le(~0, skb->data, skb->len);
fcs = ~fcs;
*skb_put (skb, 1) = fcs & 0xff;
*skb_put (skb, 1) = (fcs>> 8) & 0xff;
*skb_put (skb, 1) = (fcs>>16) & 0xff;
*skb_put (skb, 1) = (fcs>>24) & 0xff;
}
return skb;
}
static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf)
{
/* Belcarra's funky framing has other options; mostly
* TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes.
*/
dev->net->hard_header_len += 6;
dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
return usbnet_generic_cdc_bind(dev, intf);
}
/* PDA style devices are always connected if present */
static int always_connected (struct usbnet *dev)
{
return 0;
}
static const struct driver_info zaurus_sl5x00_info = {
.description = "Sharp Zaurus SL-5x00",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
.bind = zaurus_bind,
.unbind = usbnet_cdc_unbind,
.tx_fixup = zaurus_tx_fixup,
};
#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info)
static const struct driver_info zaurus_pxa_info = {
.description = "Sharp Zaurus, PXA-2xx based",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
.bind = zaurus_bind,
.unbind = usbnet_cdc_unbind,
.tx_fixup = zaurus_tx_fixup,
};
#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info)
static const struct driver_info olympus_mxl_info = {
.description = "Olympus R1000",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
.bind = zaurus_bind,
.unbind = usbnet_cdc_unbind,
.tx_fixup = zaurus_tx_fixup,
};
#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info)
/* Some more recent products using Lineo/Belcarra code will wrongly claim
* CDC MDLM conformance. They aren't conformant: data endpoints live
* in the control interface, there's no data interface, and it's not used
* to talk to a cell phone radio. But at least we can detect these two
* pseudo-classes, rather than growing this product list with entries for
* each new nonconformant product (sigh).
*/
static const u8 safe_guid[16] = {
0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
};
static const u8 blan_guid[16] = {
0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70,
0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37,
};
static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf)
{
u8 *buf = intf->cur_altsetting->extra;
int len = intf->cur_altsetting->extralen;
struct usb_cdc_mdlm_desc *desc = NULL;
struct usb_cdc_mdlm_detail_desc *detail = NULL;
while (len > 3) {
if (buf [1] != USB_DT_CS_INTERFACE)
goto next_desc;
/* use bDescriptorSubType, and just verify that we get a
* "BLAN" (or "SAFE") descriptor.
*/
switch (buf [2]) {
case USB_CDC_MDLM_TYPE:
if (desc) {
dev_dbg(&intf->dev, "extra MDLM\n");
goto bad_desc;
}
desc = (void *) buf;
if (desc->bLength != sizeof *desc) {
dev_dbg(&intf->dev, "MDLM len %u\n",
desc->bLength);
goto bad_desc;
}
/* expect bcdVersion 1.0, ignore */
if (memcmp(&desc->bGUID, blan_guid, 16)
&& memcmp(&desc->bGUID, safe_guid, 16) ) {
/* hey, this one might _really_ be MDLM! */
dev_dbg(&intf->dev, "MDLM guid\n");
goto bad_desc;
}
break;
case USB_CDC_MDLM_DETAIL_TYPE:
if (detail) {
dev_dbg(&intf->dev, "extra MDLM detail\n");
goto bad_desc;
}
detail = (void *) buf;
switch (detail->bGuidDescriptorType) {
case 0: /* "SAFE" */
if (detail->bLength != (sizeof *detail + 2))
goto bad_detail;
break;
case 1: /* "BLAN" */
if (detail->bLength != (sizeof *detail + 3))
goto bad_detail;
break;
default:
goto bad_detail;
}
/* assuming we either noticed BLAN already, or will
* find it soon, there are some data bytes here:
* - bmNetworkCapabilities (unused)
* - bmDataCapabilities (bits, see below)
* - bPad (ignored, for PADAFTER -- BLAN-only)
* bits are:
* - 0x01 -- Zaurus framing (add CRC)
* - 0x02 -- PADBEFORE (CRC includes some padding)
* - 0x04 -- PADAFTER (some padding after CRC)
* - 0x08 -- "fermat" packet mangling (for hw bugs)
* the PADBEFORE appears not to matter; we interop
* with devices that use it and those that don't.
*/
if ((detail->bDetailData[1] & ~0x02) != 0x01) {
/* bmDataCapabilites == 0 would be fine too,
* but framing is minidriver-coupled for now.
*/
bad_detail:
dev_dbg(&intf->dev,
"bad MDLM detail, %d %d %d\n",
detail->bLength,
detail->bDetailData[0],
detail->bDetailData[2]);
goto bad_desc;
}
break;
}
next_desc:
len -= buf [0]; /* bLength */
buf += buf [0];
}
if (!desc || !detail) {
dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n",
desc ? "" : "func ",
detail ? "" : "detail ");
goto bad_desc;
}
/* There's probably a CDC Ethernet descriptor there, but we can't
* rely on the Ethernet address it provides since not all vendors
* bother to make it unique. Likewise there's no point in tracking
* of the CDC event notifications.
*/
return usbnet_get_endpoints(dev, intf);
bad_desc:
dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n");
return -ENODEV;
}
static const struct driver_info bogus_mdlm_info = {
.description = "pseudo-MDLM (BLAN) device",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
.tx_fixup = zaurus_tx_fixup,
.bind = blan_mdlm_bind,
};
static const struct usb_device_id products [] = {
#define ZAURUS_MASTER_INTERFACE \
.bInterfaceClass = USB_CLASS_COMM, \
.bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
.bInterfaceProtocol = USB_CDC_PROTO_NONE
/* SA-1100 based Sharp Zaurus ("collie"), or compatible. */
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8004,
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_STRONGARM_INFO,
},
/* PXA-2xx based models are also lying-about-cdc. If you add any
* more devices that claim to be CDC Ethernet, make sure they get
* added to the blacklist in cdc_ether too.
*
* NOTE: OpenZaurus versions with 2.6 kernels won't use these entries,
* unlike the older ones with 2.4 "embedix" kernels.
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8005, /* A-300 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8006, /* B-500/SL-5600 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8007, /* C-700 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9031, /* C-750 C-760 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9032, /* SL-6000 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
/* reported with some C860 units */
.idProduct = 0x9050, /* C-860 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
},
/* At least some of the newest PXA units have very different lies about
* their standards support: they claim to be cell phones offering
* direct access to their radios! (No, they don't conform to CDC MDLM.)
*/
{
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &bogus_mdlm_info,
},
/* Olympus has some models with a Zaurus-compatible option.
* R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x07B4,
.idProduct = 0x0F02, /* R-1000 */
ZAURUS_MASTER_INTERFACE,
.driver_info = OLYMPUS_MXL_INFO,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver zaurus_driver = {
.owner = THIS_MODULE,
.name = "zaurus",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init zaurus_init(void)
{
return usb_register(&zaurus_driver);
}
module_init(zaurus_init);
static void __exit zaurus_exit(void)
{
usb_deregister(&zaurus_driver);
}
module_exit(zaurus_exit);
MODULE_AUTHOR("Pavel Machek, David Brownell");
MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products");
MODULE_LICENSE("GPL");

View file

@ -847,7 +847,6 @@ static void zd1201_tx_timeout(struct net_device *dev)
return;
dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
dev->name);
zd->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_unlink_urb(zd->tx_urb);
zd->stats.tx_errors++;
/* Restart the timeout to quiet the watchdog: */

View file

@ -453,8 +453,8 @@ static int generic_startup (struct usb_serial *serial)
priv->cbr_mask = B300;
usb_set_serial_port_data(serial->port[0], priv);
return (0);
}
return 0;
}
static int cypress_earthmate_startup (struct usb_serial *serial)
@ -464,14 +464,15 @@ static int cypress_earthmate_startup (struct usb_serial *serial)
dbg("%s", __FUNCTION__);
if (generic_startup(serial)) {
dbg("%s - Failed setting up port %d", __FUNCTION__, serial->port[0]->number);
dbg("%s - Failed setting up port %d", __FUNCTION__,
serial->port[0]->number);
return 1;
}
priv = usb_get_serial_port_data(serial->port[0]);
priv->chiptype = CT_EARTHMATE;
return (0);
return 0;
} /* cypress_earthmate_startup */
@ -482,14 +483,15 @@ static int cypress_hidcom_startup (struct usb_serial *serial)
dbg("%s", __FUNCTION__);
if (generic_startup(serial)) {
dbg("%s - Failed setting up port %d", __FUNCTION__, serial->port[0]->number);
dbg("%s - Failed setting up port %d", __FUNCTION__,
serial->port[0]->number);
return 1;
}
priv = usb_get_serial_port_data(serial->port[0]);
priv->chiptype = CT_CYPHIDCOM;
return (0);
return 0;
} /* cypress_hidcom_startup */
@ -909,7 +911,8 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
} /* cypress_ioctl */
static void cypress_set_termios (struct usb_serial_port *port, struct termios *old_termios)
static void cypress_set_termios (struct usb_serial_port *port,
struct termios *old_termios)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
@ -918,7 +921,7 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
unsigned long flags;
__u8 oldlines;
int linechange = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
tty = port->tty;
@ -931,10 +934,12 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
if (!priv->termios_initialized) {
if (priv->chiptype == CT_EARTHMATE) {
*(tty->termios) = tty_std_termios;
tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
CLOCAL;
} else if (priv->chiptype == CT_CYPHIDCOM) {
*(tty->termios) = tty_std_termios;
tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
CLOCAL;
}
priv->termios_initialized = 1;
}
@ -946,12 +951,15 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
/* check if there are new settings */
if (old_termios) {
if ((cflag != old_termios->c_cflag) ||
(RELEVANT_IFLAG(iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("%s - attempting to set new termios settings", __FUNCTION__);
/* should make a copy of this in case something goes wrong in the function, we can restore it */
(RELEVANT_IFLAG(iflag) !=
RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("%s - attempting to set new termios settings",
__FUNCTION__);
/* should make a copy of this in case something goes
* wrong in the function, we can restore it */
spin_lock_irqsave(&priv->lock, flags);
priv->tmp_termios = *(tty->termios);
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irqrestore(&priv->lock, flags);
} else {
dbg("%s - nothing to do, exiting", __FUNCTION__);
return;
@ -962,21 +970,34 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
/* set number of data bits, parity, stop bits */
/* when parity is disabled the parity type bit is ignored */
stop_bits = cflag & CSTOPB ? 1 : 0; /* 1 means 2 stop bits, 0 means 1 stop bit */
/* 1 means 2 stop bits, 0 means 1 stop bit */
stop_bits = cflag & CSTOPB ? 1 : 0;
if (cflag & PARENB) {
parity_enable = 1;
parity_type = cflag & PARODD ? 1 : 0; /* 1 means odd parity, 0 means even parity */
/* 1 means odd parity, 0 means even parity */
parity_type = cflag & PARODD ? 1 : 0;
} else
parity_enable = parity_type = 0;
if (cflag & CSIZE) {
switch (cflag & CSIZE) {
case CS5: data_bits = 0; break;
case CS6: data_bits = 1; break;
case CS7: data_bits = 2; break;
case CS8: data_bits = 3; break;
default: err("%s - CSIZE was set, but not CS5-CS8", __FUNCTION__); data_bits = 3;
case CS5:
data_bits = 0;
break;
case CS6:
data_bits = 1;
break;
case CS7:
data_bits = 2;
break;
case CS8:
data_bits = 3;
break;
default:
err("%s - CSIZE was set, but not CS5-CS8",
__FUNCTION__);
data_bits = 3;
}
} else
data_bits = 3;
@ -991,63 +1012,85 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
} else {
baud_mask = (cflag & CBAUD);
switch(baud_mask) {
case B300: dbg("%s - setting baud 300bps", __FUNCTION__); break;
case B600: dbg("%s - setting baud 600bps", __FUNCTION__); break;
case B1200: dbg("%s - setting baud 1200bps", __FUNCTION__); break;
case B2400: dbg("%s - setting baud 2400bps", __FUNCTION__); break;
case B4800: dbg("%s - setting baud 4800bps", __FUNCTION__); break;
case B9600: dbg("%s - setting baud 9600bps", __FUNCTION__); break;
case B19200: dbg("%s - setting baud 19200bps", __FUNCTION__); break;
case B38400: dbg("%s - setting baud 38400bps", __FUNCTION__); break;
case B57600: dbg("%s - setting baud 57600bps", __FUNCTION__); break;
case B115200: dbg("%s - setting baud 115200bps", __FUNCTION__); break;
default: dbg("%s - unknown masked baud rate", __FUNCTION__);
case B300:
dbg("%s - setting baud 300bps", __FUNCTION__);
break;
case B600:
dbg("%s - setting baud 600bps", __FUNCTION__);
break;
case B1200:
dbg("%s - setting baud 1200bps", __FUNCTION__);
break;
case B2400:
dbg("%s - setting baud 2400bps", __FUNCTION__);
break;
case B4800:
dbg("%s - setting baud 4800bps", __FUNCTION__);
break;
case B9600:
dbg("%s - setting baud 9600bps", __FUNCTION__);
break;
case B19200:
dbg("%s - setting baud 19200bps", __FUNCTION__);
break;
case B38400:
dbg("%s - setting baud 38400bps", __FUNCTION__);
break;
case B57600:
dbg("%s - setting baud 57600bps", __FUNCTION__);
break;
case B115200:
dbg("%s - setting baud 115200bps", __FUNCTION__);
break;
default:
dbg("%s - unknown masked baud rate", __FUNCTION__);
}
priv->line_control = (CONTROL_DTR | CONTROL_RTS);
}
spin_unlock_irqrestore(&priv->lock, flags);
dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, %d data_bits (+5)", __FUNCTION__,
stop_bits, parity_enable, parity_type, data_bits);
cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable,
parity_type, 0, CYPRESS_SET_CONFIG);
dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, "
"%d data_bits (+5)", __FUNCTION__, stop_bits,
parity_enable, parity_type, data_bits);
/* we perform a CYPRESS_GET_CONFIG so that the current settings are filled into the private structure
* this should confirm that all is working if it returns what we just set */
cypress_serial_control(port, baud_mask, data_bits, stop_bits,
parity_enable, parity_type, 0, CYPRESS_SET_CONFIG);
/* we perform a CYPRESS_GET_CONFIG so that the current settings are
* filled into the private structure this should confirm that all is
* working if it returns what we just set */
cypress_serial_control(port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
/* Here we can define custom tty settings for devices
*
* the main tty termios flag base comes from empeg.c
*/
/* Here we can define custom tty settings for devices; the main tty
* termios flag base comes from empeg.c */
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irqsave(&priv->lock, flags);
if ( (priv->chiptype == CT_EARTHMATE) && (priv->baud_rate == 4800) ) {
dbg("Using custom termios settings for a baud rate of 4800bps.");
dbg("Using custom termios settings for a baud rate of "
"4800bps.");
/* define custom termios settings for NMEA protocol */
tty->termios->c_iflag /* input modes - */
&= ~(IGNBRK /* disable ignore break */
| BRKINT /* disable break causes interrupt */
| PARMRK /* disable mark parity errors */
| ISTRIP /* disable clear high bit of input characters */
| INLCR /* disable translate NL to CR */
| IGNCR /* disable ignore CR */
| ICRNL /* disable translate CR to NL */
| IXON); /* disable enable XON/XOFF flow control */
tty->termios->c_oflag /* output modes */
&= ~OPOST; /* disable postprocess output characters */
tty->termios->c_lflag /* line discipline modes */
&= ~(ECHO /* disable echo input characters */
| ECHONL /* disable echo new line */
| ICANON /* disable erase, kill, werase, and rprnt special characters */
| ISIG /* disable interrupt, quit, and suspend special characters */
| IEXTEN); /* disable non-POSIX special characters */
&= ~(IGNBRK /* disable ignore break */
| BRKINT /* disable break causes interrupt */
| PARMRK /* disable mark parity errors */
| ISTRIP /* disable clear high bit of input char */
| INLCR /* disable translate NL to CR */
| IGNCR /* disable ignore CR */
| ICRNL /* disable translate CR to NL */
| IXON); /* disable enable XON/XOFF flow control */
tty->termios->c_oflag /* output modes */
&= ~OPOST; /* disable postprocess output char */
tty->termios->c_lflag /* line discipline modes */
&= ~(ECHO /* disable echo input characters */
| ECHONL /* disable echo new line */
| ICANON /* disable erase, kill, werase, and rprnt
special characters */
| ISIG /* disable interrupt, quit, and suspend
special characters */
| IEXTEN); /* disable non-POSIX special characters */
} /* CT_CYPHIDCOM: Application should handle this for device */
linechange = (priv->line_control != oldlines);
@ -1060,7 +1103,7 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
}
} /* cypress_set_termios */
/* returns amount of data still left in soft buffer */
static int cypress_chars_in_buffer(struct usb_serial_port *port)
{
@ -1088,7 +1131,7 @@ static void cypress_throttle (struct usb_serial_port *port)
spin_lock_irqsave(&priv->lock, flags);
priv->rx_flags = THROTTLED;
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irqrestore(&priv->lock, flags);
}
@ -1110,7 +1153,8 @@ static void cypress_unthrottle (struct usb_serial_port *port)
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
dev_err(&port->dev, "%s - failed submitting read urb, "
"error %d\n", __FUNCTION__, result);
}
}
@ -1122,7 +1166,7 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
char tty_flag = TTY_NORMAL;
char tty_flag = TTY_NORMAL;
int havedata = 0;
int bytes = 0;
int result;
@ -1131,7 +1175,8 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status) {
dbg("%s - nonzero read status received: %d", __FUNCTION__, urb->status);
dbg("%s - nonzero read status received: %d", __FUNCTION__,
urb->status);
return;
}
@ -1155,51 +1200,55 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
case 32:
/* This is for the CY7C64013... */
priv->current_status = data[0] & 0xF8;
bytes = data[1]+2;
i=2;
bytes = data[1] + 2;
i = 2;
if (bytes > 2)
havedata = 1;
break;
case 8:
/* This is for the CY7C63743... */
priv->current_status = data[0] & 0xF8;
bytes = (data[0] & 0x07)+1;
i=1;
bytes = (data[0] & 0x07) + 1;
i = 1;
if (bytes > 1)
havedata = 1;
break;
default:
dbg("%s - wrong packet size - received %d bytes", __FUNCTION__, urb->actual_length);
dbg("%s - wrong packet size - received %d bytes",
__FUNCTION__, urb->actual_length);
spin_unlock_irqrestore(&priv->lock, flags);
goto continue_read;
}
spin_unlock_irqrestore(&priv->lock, flags);
usb_serial_debug_data (debug, &port->dev, __FUNCTION__, urb->actual_length, data);
usb_serial_debug_data (debug, &port->dev, __FUNCTION__,
urb->actual_length, data);
spin_lock_irqsave(&priv->lock, flags);
/* check to see if status has changed */
if (priv != NULL) {
if (priv->current_status != priv->prev_status) {
priv->diff_status |= priv->current_status ^ priv->prev_status;
priv->diff_status |= priv->current_status ^
priv->prev_status;
wake_up_interruptible(&priv->delta_msr_wait);
priv->prev_status = priv->current_status;
}
}
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irqrestore(&priv->lock, flags);
/* hangup, as defined in acm.c... this might be a bad place for it though */
if (tty && !(tty->termios->c_cflag & CLOCAL) && !(priv->current_status & UART_CD)) {
/* hangup, as defined in acm.c... this might be a bad place for it
* though */
if (tty && !(tty->termios->c_cflag & CLOCAL) &&
!(priv->current_status & UART_CD)) {
dbg("%s - calling hangup", __FUNCTION__);
tty_hangup(tty);
goto continue_read;
}
/* There is one error bit... I'm assuming it is a parity error indicator
* as the generic firmware will set this bit to 1 if a parity error occurs.
* I can not find reference to any other error events.
*
*/
/* There is one error bit... I'm assuming it is a parity error
* indicator as the generic firmware will set this bit to 1 if a
* parity error occurs.
* I can not find reference to any other error events. */
spin_lock_irqsave(&priv->lock, flags);
if (priv->current_status & CYP_ERROR) {
spin_unlock_irqrestore(&priv->lock, flags);
@ -1211,7 +1260,8 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
/* process read if there is data other than line status */
if (tty && (bytes > i)) {
for (; i < bytes ; ++i) {
dbg("pushing byte number %d - %d - %c",i,data[i],data[i]);
dbg("pushing byte number %d - %d - %c", i, data[i],
data[i]);
if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty_flip_buffer_push(tty);
}
@ -1221,25 +1271,28 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
}
spin_lock_irqsave(&priv->lock, flags);
priv->bytes_in += bytes; /* control and status byte(s) are also counted */
/* control and status byte(s) are also counted */
priv->bytes_in += bytes;
spin_unlock_irqrestore(&priv->lock, flags);
continue_read:
/* Continue trying to always read... unless the port has closed. */
/* Continue trying to always read... unless the port has closed. */
if (port->open_count > 0) {
usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
port->interrupt_in_urb->transfer_buffer,
port->interrupt_in_urb->transfer_buffer_length,
cypress_read_int_callback, port,
interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
usb_rcvintpipe(port->serial->dev,
port->interrupt_in_endpointAddress),
port->interrupt_in_urb->transfer_buffer,
port->interrupt_in_urb->transfer_buffer_length,
cypress_read_int_callback, port, interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting "
"read urb, error %d\n", __FUNCTION__,
result);
}
return;
} /* cypress_read_int_callback */

View file

@ -269,6 +269,8 @@
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
static int debug;
static __u16 vendor = FTDI_VID;
static __u16 product;
/* struct ftdi_sio_quirk is used by devices requiring special attention. */
struct ftdi_sio_quirk {
@ -407,6 +409,34 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
/*
* These will probably use user-space drivers. Uncomment them if
* you need them or use the user-specified vendor/product module
* parameters (see ftdi_sio.h for the numbers). Make a fuss if
* you think the driver should recognize any of them by default.
*/
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@ -418,6 +448,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
{ USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
{ USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
@ -427,12 +458,21 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
{ } /* Terminating entry */
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, id_table_combined);
@ -2030,6 +2070,15 @@ static int __init ftdi_init (void)
int retval;
dbg("%s", __FUNCTION__);
if (vendor > 0 && product > 0) {
/* Add user specified VID/PID to reserved element of table. */
int i;
for (i = 0; id_table_combined[i].idVendor; i++)
;
id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
id_table_combined[i].idVendor = vendor;
id_table_combined[i].idProduct = product;
}
retval = usb_serial_register(&ftdi_sio_device);
if (retval)
goto failed_sio_register;
@ -2066,4 +2115,9 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
__MODULE_STRING(FTDI_VID)")");
module_param(product, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified product ID");

View file

@ -142,10 +142,43 @@
/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
/* ELV USB Module UO100 (PID sent by Stefan Frings) */
#define FTDI_ELV_UO100_PID 0xFB58 /* Product Id */
/* ELV USB Module UM100 (PID sent by Arnim Laeuger) */
#define FTDI_ELV_UM100_PID 0xFB5A /* Product Id */
/*
* ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
* All of these devices use FTDI's vendor ID (0x0403).
*
* The previously included PID for the UO 100 module was incorrect.
* In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58).
*
* Armin Laeuger originally sent the PID for the UM 100 module.
*/
#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */
#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */
#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */
#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */
/* Additional ELV PIDs that default to using the FTDI D2XX drivers on
* MS Windows, rather than the FTDI Virtual Com Port drivers.
* Maybe these will be easier to use with the libftdi/libusb user-space
* drivers, or possibly the Comedi drivers in some cases. */
#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */
#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */
#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperartur-Feuchte Messgeraet (TFM 100) */
#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkurh (UDF 77) */
#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */
#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */
#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */
#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */
#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */
#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */
#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */
#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */
#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */
#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */
#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */
#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */
#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */
#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */
#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */
/*
* Definitions for ID TECH (www.idt-net.com) devices
@ -222,6 +255,7 @@
*/
#define FALCOM_VID 0x0F94 /* Vendor Id */
#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */
#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */
/*
* SUUNTO product ids
@ -276,6 +310,18 @@
*/
#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */
/*
* Xsens Technologies BV products (http://www.xsens.com).
*/
#define XSENS_CONVERTER_0_PID 0xD388
#define XSENS_CONVERTER_1_PID 0xD389
#define XSENS_CONVERTER_2_PID 0xD38A
#define XSENS_CONVERTER_3_PID 0xD38B
#define XSENS_CONVERTER_4_PID 0xD38C
#define XSENS_CONVERTER_5_PID 0xD38D
#define XSENS_CONVERTER_6_PID 0xD38E
#define XSENS_CONVERTER_7_PID 0xD38F
/*
* Evolution Robotics products (http://www.evolution.com/).
* Submitted by Shawn M. Lavelle.

View file

@ -383,11 +383,8 @@ static int keyspan_write(struct usb_serial_port *port,
dbg("%s - endpoint %d flip %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), flip);
if (this_urb->status == -EINPROGRESS) {
if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
break;
if (time_before(jiffies, p_priv->tx_start_time[flip] + 10 * HZ))
break;
this_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_unlink_urb(this_urb);
break;
}
@ -402,7 +399,6 @@ static int keyspan_write(struct usb_serial_port *port,
/* send the data out the bulk port */
this_urb->transfer_buffer_length = todo + dataOffset;
this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
this_urb->dev = port->serial->dev;
if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
dbg("usb_submit_urb(write bulk) failed (%d)", err);
@ -1119,10 +1115,8 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
static inline void stop_urb(struct urb *urb)
{
if (urb && urb->status == -EINPROGRESS) {
urb->transfer_flags &= ~URB_ASYNC_UNLINK;
if (urb && urb->status == -EINPROGRESS)
usb_kill_urb(urb);
}
}
static void keyspan_close(struct usb_serial_port *port, struct file *filp)

View file

@ -45,29 +45,29 @@
#include "usb-serial.h"
/* Function prototypes */
static int option_open (struct usb_serial_port *port, struct file *filp);
static void option_close (struct usb_serial_port *port, struct file *filp);
static int option_startup (struct usb_serial *serial);
static void option_shutdown (struct usb_serial *serial);
static void option_rx_throttle (struct usb_serial_port *port);
static void option_rx_unthrottle (struct usb_serial_port *port);
static int option_write_room (struct usb_serial_port *port);
static int option_open(struct usb_serial_port *port, struct file *filp);
static void option_close(struct usb_serial_port *port, struct file *filp);
static int option_startup(struct usb_serial *serial);
static void option_shutdown(struct usb_serial *serial);
static void option_rx_throttle(struct usb_serial_port *port);
static void option_rx_unthrottle(struct usb_serial_port *port);
static int option_write_room(struct usb_serial_port *port);
static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
static int option_write (struct usb_serial_port *port,
const unsigned char *buf, int count);
static int option_write(struct usb_serial_port *port,
const unsigned char *buf, int count);
static int option_chars_in_buffer (struct usb_serial_port *port);
static int option_ioctl (struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg);
static void option_set_termios (struct usb_serial_port *port,
struct termios *old);
static void option_break_ctl (struct usb_serial_port *port, int break_state);
static int option_tiocmget (struct usb_serial_port *port, struct file *file);
static int option_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static int option_send_setup (struct usb_serial_port *port);
static int option_chars_in_buffer(struct usb_serial_port *port);
static int option_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg);
static void option_set_termios(struct usb_serial_port *port,
struct termios *old);
static void option_break_ctl(struct usb_serial_port *port, int break_state);
static int option_tiocmget(struct usb_serial_port *port, struct file *file);
static int option_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static int option_send_setup(struct usb_serial_port *port);
/* Vendor and product IDs */
#define OPTION_VENDOR_ID 0x0AF0
@ -76,7 +76,6 @@ static int option_send_setup (struct usb_serial_port *port);
#define OPTION_PRODUCT_FUSION 0x6000
#define OPTION_PRODUCT_FUSION2 0x6300
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
@ -129,7 +128,6 @@ static int debug;
#define debug 0
#endif
/* per port private data */
#define N_IN_URB 4
@ -156,10 +154,8 @@ struct option_port_private {
unsigned long tx_start_time[N_OUT_URB];
};
/* Functions used by new usb-serial code. */
static int __init
option_init (void)
static int __init option_init(void)
{
int retval;
retval = usb_serial_register(&option_3port_device);
@ -179,8 +175,7 @@ failed_3port_device_register:
return retval;
}
static void __exit
option_exit (void)
static void __exit option_exit(void)
{
usb_deregister (&option_driver);
usb_serial_deregister (&option_3port_device);
@ -189,39 +184,31 @@ option_exit (void)
module_init(option_init);
module_exit(option_exit);
static void
option_rx_throttle (struct usb_serial_port *port)
static void option_rx_throttle(struct usb_serial_port *port)
{
dbg("%s", __FUNCTION__);
}
static void
option_rx_unthrottle (struct usb_serial_port *port)
static void option_rx_unthrottle(struct usb_serial_port *port)
{
dbg("%s", __FUNCTION__);
}
static void
option_break_ctl (struct usb_serial_port *port, int break_state)
static void option_break_ctl(struct usb_serial_port *port, int break_state)
{
/* Unfortunately, I don't know how to send a break */
dbg("%s", __FUNCTION__);
}
static void
option_set_termios (struct usb_serial_port *port,
struct termios *old_termios)
static void option_set_termios(struct usb_serial_port *port,
struct termios *old_termios)
{
dbg("%s", __FUNCTION__);
option_send_setup(port);
}
static int
option_tiocmget (struct usb_serial_port *port, struct file *file)
static int option_tiocmget(struct usb_serial_port *port, struct file *file)
{
unsigned int value;
struct option_port_private *portdata;
@ -238,9 +225,8 @@ option_tiocmget (struct usb_serial_port *port, struct file *file)
return value;
}
static int
option_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
static int option_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
{
struct option_port_private *portdata;
@ -258,17 +244,15 @@ option_tiocmset (struct usb_serial_port *port, struct file *file,
return option_send_setup(port);
}
static int
option_ioctl (struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
static int option_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
return -ENOIOCTLCMD;
}
/* Write */
static int
option_write (struct usb_serial_port *port,
const unsigned char *buf, int count)
static int option_write(struct usb_serial_port *port,
const unsigned char *buf, int count)
{
struct option_port_private *portdata;
int i;
@ -289,28 +273,29 @@ option_write (struct usb_serial_port *port,
this_urb = portdata->out_urbs[i];
if (this_urb->status == -EINPROGRESS) {
if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
if (time_before(jiffies,
portdata->tx_start_time[i] + 10 * HZ))
continue;
if (time_before(jiffies, portdata->tx_start_time[i] + 10 * HZ))
continue;
this_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_unlink_urb(this_urb);
continue;
}
if (this_urb->status != 0)
dbg("usb_write %p failed (err=%d)", this_urb, this_urb->status);
dbg("usb_write %p failed (err=%d)",
this_urb, this_urb->status);
dbg("%s: endpoint %d buf %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), i);
dbg("%s: endpoint %d buf %d", __FUNCTION__,
usb_pipeendpoint(this_urb->pipe), i);
/* send the data */
memcpy (this_urb->transfer_buffer, buf, todo);
this_urb->transfer_buffer_length = todo;
this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
this_urb->dev = port->serial->dev;
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err) {
dbg("usb_submit_urb %p (write bulk) failed (%d, has %d)", this_urb, err, this_urb->status);
dbg("usb_submit_urb %p (write bulk) failed "
"(%d, has %d)", this_urb,
err, this_urb->status);
continue;
}
portdata->tx_start_time[i] = jiffies;
@ -323,8 +308,7 @@ option_write (struct usb_serial_port *port,
return count;
}
static void
option_indat_callback (struct urb *urb, struct pt_regs *regs)
static void option_indat_callback(struct urb *urb, struct pt_regs *regs)
{
int i, err;
int endpoint;
@ -357,14 +341,14 @@ option_indat_callback (struct urb *urb, struct pt_regs *regs)
if (port->open_count && urb->status != -ESHUTDOWN) {
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
printk(KERN_ERR "%s: resubmit read urb failed. (%d)", __FUNCTION__, err);
printk(KERN_ERR "%s: resubmit read urb failed. "
"(%d)", __FUNCTION__, err);
}
}
return;
}
static void
option_outdat_callback (struct urb *urb, struct pt_regs *regs)
static void option_outdat_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port;
@ -376,8 +360,7 @@ option_outdat_callback (struct urb *urb, struct pt_regs *regs)
schedule_work(&port->work);
}
static void
option_instat_callback (struct urb *urb, struct pt_regs *regs)
static void option_instat_callback(struct urb *urb, struct pt_regs *regs)
{
int err;
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
@ -395,10 +378,12 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
dbg("%s: NULL req_pkt\n", __FUNCTION__);
return;
}
if ((req_pkt->bRequestType == 0xA1) && (req_pkt->bRequest == 0x20)) {
if ((req_pkt->bRequestType == 0xA1) &&
(req_pkt->bRequest == 0x20)) {
int old_dcd_state;
unsigned char signals = *((unsigned char *)
urb->transfer_buffer + sizeof(struct usb_ctrlrequest));
urb->transfer_buffer +
sizeof(struct usb_ctrlrequest));
dbg("%s: signal x%x", __FUNCTION__, signals);
@ -408,12 +393,13 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
if (port->tty && !C_CLOCAL(port->tty)
&& old_dcd_state && !portdata->dcd_state) {
if (port->tty && !C_CLOCAL(port->tty) &&
old_dcd_state && !portdata->dcd_state)
tty_hangup(port->tty);
}
} else
dbg("%s: type %x req %x", __FUNCTION__, req_pkt->bRequestType,req_pkt->bRequest);
} else {
dbg("%s: type %x req %x", __FUNCTION__,
req_pkt->bRequestType,req_pkt->bRequest);
}
} else
dbg("%s: error %d", __FUNCTION__, urb->status);
@ -422,13 +408,12 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
dbg("%s: resubmit intr urb failed. (%d)", __FUNCTION__, err);
dbg("%s: resubmit intr urb failed. (%d)",
__FUNCTION__, err);
}
}
static int
option_write_room (struct usb_serial_port *port)
static int option_write_room(struct usb_serial_port *port)
{
struct option_port_private *portdata;
int i;
@ -447,9 +432,7 @@ option_write_room (struct usb_serial_port *port)
return data_len;
}
static int
option_chars_in_buffer (struct usb_serial_port *port)
static int option_chars_in_buffer(struct usb_serial_port *port)
{
struct option_port_private *portdata;
int i;
@ -467,9 +450,7 @@ option_chars_in_buffer (struct usb_serial_port *port)
return data_len;
}
static int
option_open (struct usb_serial_port *port, struct file *filp)
static int option_open(struct usb_serial_port *port, struct file *filp)
{
struct option_port_private *portdata;
struct usb_serial *serial = port->serial;
@ -490,17 +471,21 @@ option_open (struct usb_serial_port *port, struct file *filp)
if (! urb)
continue;
if (urb->dev != serial->dev) {
dbg("%s: dev %p != %p", __FUNCTION__, urb->dev, serial->dev);
dbg("%s: dev %p != %p", __FUNCTION__,
urb->dev, serial->dev);
continue;
}
/* make sure endpoint data toggle is synchronized with the device */
/*
* make sure endpoint data toggle is synchronized with the
* device
*/
usb_clear_halt(urb->dev, urb->pipe);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
dbg("%s: submit urb %d failed (%d) %d", __FUNCTION__, i, err,
dbg("%s: submit urb %d failed (%d) %d",
__FUNCTION__, i, err,
urb->transfer_buffer_length);
}
}
@ -511,7 +496,8 @@ option_open (struct usb_serial_port *port, struct file *filp)
if (! urb)
continue;
urb->dev = serial->dev;
/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), 0); */
}
port->tty->low_latency = 1;
@ -521,17 +507,13 @@ option_open (struct usb_serial_port *port, struct file *filp)
return (0);
}
static inline void
stop_urb (struct urb *urb)
static inline void stop_urb(struct urb *urb)
{
if (urb && urb->status == -EINPROGRESS) {
urb->transfer_flags &= ~URB_ASYNC_UNLINK;
if (urb && urb->status == -EINPROGRESS)
usb_kill_urb(urb);
}
}
static void
option_close (struct usb_serial_port *port, struct file *filp)
static void option_close(struct usb_serial_port *port, struct file *filp)
{
int i;
struct usb_serial *serial = port->serial;
@ -555,12 +537,10 @@ option_close (struct usb_serial_port *port, struct file *filp)
port->tty = NULL;
}
/* Helper functions used by option_setup_urbs */
static struct urb *
option_setup_urb (struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
void (*callback)(struct urb *, struct pt_regs *regs))
static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
void (*callback)(struct urb *, struct pt_regs *regs))
{
struct urb *urb;
@ -582,8 +562,7 @@ option_setup_urb (struct usb_serial *serial, int endpoint,
}
/* Setup urbs */
static void
option_setup_urbs (struct usb_serial *serial)
static void option_setup_urbs(struct usb_serial *serial)
{
int j;
struct usb_serial_port *port;
@ -609,9 +588,7 @@ option_setup_urbs (struct usb_serial *serial)
}
}
static int
option_send_setup (struct usb_serial_port *port)
static int option_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct option_port_private *portdata;
@ -627,16 +604,15 @@ option_send_setup (struct usb_serial_port *port)
if (portdata->rts_state)
val |= 0x02;
return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
}
return 0;
}
static int
option_startup (struct usb_serial *serial)
static int option_startup(struct usb_serial *serial)
{
int i, err;
struct usb_serial_port *port;
@ -647,9 +623,10 @@ option_startup (struct usb_serial *serial)
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
portdata = kmalloc(sizeof(struct option_port_private), GFP_KERNEL);
portdata = kmalloc(sizeof(*portdata), GFP_KERNEL);
if (!portdata) {
dbg("%s: kmalloc for option_port_private (%d) failed!.", __FUNCTION__, i);
dbg("%s: kmalloc for option_port_private (%d) failed!.",
__FUNCTION__, i);
return (1);
}
memset(portdata, 0, sizeof(struct option_port_private));
@ -660,7 +637,8 @@ option_startup (struct usb_serial *serial)
continue;
err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (err)
dbg("%s: submit irq_in urb failed %d", __FUNCTION__, err);
dbg("%s: submit irq_in urb failed %d",
__FUNCTION__, err);
}
option_setup_urbs(serial);
@ -668,8 +646,7 @@ option_startup (struct usb_serial *serial)
return (0);
}
static void
option_shutdown (struct usb_serial *serial)
static void option_shutdown(struct usb_serial *serial)
{
int i, j;
struct usb_serial_port *port;

View file

@ -538,8 +538,10 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
dbg("%s - port %d", __FUNCTION__, port->number);
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
if (priv->type != HX) {
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
}
buf = kmalloc(10, GFP_KERNEL);
if (buf==NULL)

View file

@ -531,7 +531,7 @@ bailout_kref_put:
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
if (!port)
return;
@ -561,7 +561,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
int retval = -EINVAL;
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
@ -580,7 +580,7 @@ exit:
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
int retval = -EINVAL;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -599,7 +599,7 @@ exit:
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
int retval = -EINVAL;
dbg("%s = port %d", __FUNCTION__, port->number);
@ -618,7 +618,7 @@ exit:
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -634,7 +634,7 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -650,7 +650,7 @@ static void serial_unthrottle (struct tty_struct * tty)
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
@ -672,7 +672,7 @@ exit:
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -688,7 +688,7 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -749,7 +749,7 @@ done:
static int serial_tiocmget (struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -768,7 +768,7 @@ exit:
static int serial_tiocmset (struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -786,7 +786,7 @@ exit:
void usb_serial_port_softint(void *private)
{
struct usb_serial_port *port = (struct usb_serial_port *)private;
struct usb_serial_port *port = private;
struct tty_struct *tty;
dbg("%s - port %d", __FUNCTION__, port->number);

View file

@ -111,3 +111,15 @@ config USB_STORAGE_JUMPSHOT
Say Y here to include additional code to support the Lexar Jumpshot
USB CompactFlash reader.
config USB_STORAGE_ONETOUCH
bool "Support OneTouch Button on Maxtor Hard Drives (EXPERIMENTAL)"
depends on USB_STORAGE && INPUT_EVDEV && EXPERIMENTAL
help
Say Y here to include additional code to support the Maxtor OneTouch
USB hard drive's onetouch button.
This code registers the button on the front of Maxtor OneTouch USB
hard drive's as an input device. An action can be associated with
this input in any keybinding software. (e.g. gnome's keyboard short-
cuts)

View file

@ -18,6 +18,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200) += isd200.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)

View file

@ -0,0 +1,210 @@
/*
* Support for the Maxtor OneTouch USB hard drive's button
*
* Current development and maintenance by:
* Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu>
*
* Initial work by:
* Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se>
*
* Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann)
*
*/
/*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb_ch9.h>
#include <linux/usb_input.h>
#include "usb.h"
#include "onetouch.h"
#include "debug.h"
void onetouch_release_input(void *onetouch_);
struct usb_onetouch {
char name[128];
char phys[64];
struct input_dev dev; /* input device interface */
struct usb_device *udev; /* usb device */
struct urb *irq; /* urb for interrupt in report */
unsigned char *data; /* input data */
dma_addr_t data_dma;
};
static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs)
{
struct usb_onetouch *onetouch = urb->context;
signed char *data = onetouch->data;
struct input_dev *dev = &onetouch->dev;
int status;
switch (urb->status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
return;
/* -EPIPE: should clear the halt */
default: /* error */
goto resubmit;
}
input_regs(dev, regs);
input_report_key(&onetouch->dev, ONETOUCH_BUTTON,
data[0] & 0x02);
input_sync(dev);
resubmit:
status = usb_submit_urb (urb, SLAB_ATOMIC);
if (status)
err ("can't resubmit intr, %s-%s/input0, status %d",
onetouch->udev->bus->bus_name,
onetouch->udev->devpath, status);
}
static int usb_onetouch_open(struct input_dev *dev)
{
struct usb_onetouch *onetouch = dev->private;
onetouch->irq->dev = onetouch->udev;
if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
err("usb_submit_urb failed");
return -EIO;
}
return 0;
}
static void usb_onetouch_close(struct input_dev *dev)
{
struct usb_onetouch *onetouch = dev->private;
usb_kill_urb(onetouch->irq);
}
int onetouch_connect_input(struct us_data *ss)
{
struct usb_device *udev = ss->pusb_dev;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_onetouch *onetouch;
int pipe, maxp;
char path[64];
interface = ss->pusb_intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 3)
return -ENODEV;
endpoint = &interface->endpoint[2].desc;
if(!(endpoint->bEndpointAddress & USB_DIR_IN))
return -ENODEV;
if((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_INT)
return -ENODEV;
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
if (!(onetouch = kcalloc(1, sizeof(struct usb_onetouch), GFP_KERNEL)))
return -ENOMEM;
onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN,
SLAB_ATOMIC, &onetouch->data_dma);
if (!onetouch->data){
kfree(onetouch);
return -ENOMEM;
}
onetouch->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!onetouch->irq){
kfree(onetouch);
usb_buffer_free(udev, ONETOUCH_PKT_LEN,
onetouch->data, onetouch->data_dma);
return -ENODEV;
}
onetouch->udev = udev;
set_bit(EV_KEY, onetouch->dev.evbit);
set_bit(ONETOUCH_BUTTON, onetouch->dev.keybit);
clear_bit(0, onetouch->dev.keybit);
onetouch->dev.private = onetouch;
onetouch->dev.open = usb_onetouch_open;
onetouch->dev.close = usb_onetouch_close;
usb_make_path(udev, path, sizeof(path));
sprintf(onetouch->phys, "%s/input0", path);
onetouch->dev.name = onetouch->name;
onetouch->dev.phys = onetouch->phys;
usb_to_input_id(udev, &onetouch->dev.id);
onetouch->dev.dev = &udev->dev;
if (udev->manufacturer)
strcat(onetouch->name, udev->manufacturer);
if (udev->product)
sprintf(onetouch->name, "%s %s", onetouch->name,
udev->product);
if (!strlen(onetouch->name))
sprintf(onetouch->name, "Maxtor Onetouch %04x:%04x",
onetouch->dev.id.vendor, onetouch->dev.id.product);
usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data,
(maxp > 8 ? 8 : maxp),
usb_onetouch_irq, onetouch, endpoint->bInterval);
onetouch->irq->transfer_dma = onetouch->data_dma;
onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
ss->extra_destructor = onetouch_release_input;
ss->extra = onetouch;
input_register_device(&onetouch->dev);
printk(KERN_INFO "usb-input: %s on %s\n", onetouch->dev.name, path);
return 0;
}
void onetouch_release_input(void *onetouch_)
{
struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
if (onetouch) {
usb_kill_urb(onetouch->irq);
input_unregister_device(&onetouch->dev);
usb_free_urb(onetouch->irq);
usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN,
onetouch->data, onetouch->data_dma);
printk(KERN_INFO "usb-input: deregistering %s\n",
onetouch->dev.name);
}
}

View file

@ -0,0 +1,9 @@
#ifndef _ONETOUCH_H_
#define _ONETOUCH_H_
#define ONETOUCH_PKT_LEN 0x02
#define ONETOUCH_BUTTON KEY_PROG1
int onetouch_connect_input(struct us_data *ss);
#endif

View file

@ -156,6 +156,14 @@ static int slave_configure(struct scsi_device *sdev)
if (us->flags & US_FL_FIX_CAPACITY)
sdev->fix_capacity = 1;
/* Some devices report a SCSI revision level above 2 but are
* unable to handle the REPORT LUNS command (for which
* support is mandatory at level 3). Since we already have
* a Get-Max-LUN request, we won't lose much by setting the
* revision level down to 2. The only devices that would be
* affected are those with sparse LUNs. */
sdev->scsi_level = SCSI_2;
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs,
* recoverable or not. Setting this flag tells the SCSI

View file

@ -839,34 +839,31 @@ static int usbat_identify_device(struct us_data *us,
rc = usbat_device_reset(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
msleep(25);
/*
* By examining the device signature after a reset, we can identify
* whether the device supports the ATAPI packet interface.
* The flash-devices do not support this, whereas the HP CDRW's obviously
* do.
*
* This method is not ideal, but works because no other devices have been
* produced based on the USBAT/USBAT02.
*
* Section 9.1 of the ATAPI-4 spec states (amongst other things) that
* after a device reset, a Cylinder low of 0x14 indicates that the device
* does support packet commands.
* In attempt to distinguish between HP CDRW's and Flash readers, we now
* execute the IDENTIFY PACKET DEVICE command. On ATA devices (i.e. flash
* readers), this command should fail with error. On ATAPI devices (i.e.
* CDROM drives), it should succeed.
*/
rc = usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, &status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
rc = usbat_write(us, USBAT_ATA, USBAT_ATA_CMD, 0xA1);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("usbat_identify_device: Cylinder low is %02X\n", status);
rc = usbat_get_status(us, &status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (status == 0x14) {
// Check for error bit
if (status & 0x01) {
// Device is a CompactFlash reader/writer
US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
info->devicetype = USBAT_DEV_FLASH;
} else {
// Device is HP 8200
US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
info->devicetype = USBAT_DEV_HP8200;
} else {
// Device is a CompactFlash reader/writer
US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
info->devicetype = USBAT_DEV_FLASH;
}
return USB_STOR_TRANSPORT_GOOD;
@ -1239,16 +1236,10 @@ static int usbat_select_and_test_registers(struct us_data *us)
{
int selector;
unsigned char *status = us->iobuf;
unsigned char max_selector = 0xB0;
if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
max_selector = 0xA0;
// try device = master, then device = slave.
for (selector = 0xA0; selector <= max_selector; selector += 0x10) {
if (usbat_get_device_type(us) == USBAT_DEV_HP8200 &&
usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) !=
for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@ -1334,60 +1325,30 @@ int init_usbat(struct us_data *us)
US_DEBUGP("INIT 3\n");
// At this point, we need to detect which device we are using
if (usbat_set_transport(us, info))
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 4\n");
if (usbat_get_device_type(us) == USBAT_DEV_HP8200) {
msleep(250);
// Write 0x80 to ISA port 0x3F
rc = usbat_write(us, USBAT_ISA, 0x3F, 0x80);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 5\n");
// Read ISA port 0x27
rc = usbat_read(us, USBAT_ISA, 0x27, status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 6\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 7\n");
}
rc = usbat_select_and_test_registers(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
US_DEBUGP("INIT 8\n");
US_DEBUGP("INIT 4\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 9\n");
US_DEBUGP("INIT 5\n");
// Enable peripheral control signals and card detect
rc = usbat_device_enable_cdt(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
US_DEBUGP("INIT 10\n");
US_DEBUGP("INIT 6\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 11\n");
US_DEBUGP("INIT 7\n");
msleep(1400);
@ -1395,13 +1356,19 @@ int init_usbat(struct us_data *us)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 12\n");
US_DEBUGP("INIT 8\n");
rc = usbat_select_and_test_registers(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
US_DEBUGP("INIT 13\n");
US_DEBUGP("INIT 9\n");
// At this point, we need to detect which device we are using
if (usbat_set_transport(us, info))
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 10\n");
if (usbat_get_device_type(us) == USBAT_DEV_FLASH) {
subcountH = 0x02;
@ -1412,7 +1379,7 @@ int init_usbat(struct us_data *us)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 14\n");
US_DEBUGP("INIT 11\n");
return USB_STOR_TRANSPORT_GOOD;
}

View file

@ -96,8 +96,8 @@
* or before the URB_ACTIVE bit was set. If so, it's essential to cancel
* the URB if it hasn't been cancelled already (i.e., if the URB_ACTIVE bit
* is still set). Either way, the function must then wait for the URB to
* finish. Note that because the URB_ASYNC_UNLINK flag is set, the URB can
* still be in progress even after a call to usb_unlink_urb() returns.
* finish. Note that the URB can still be in progress even after a call to
* usb_unlink_urb() returns.
*
* The idea is that (1) once the ABORTING or DISCONNECTING bit is set,
* either the stop_transport() function or the submitting function
@ -158,8 +158,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
* hasn't been mapped for DMA. Yes, this is clunky, but it's
* easier than always having the caller tell us whether the
* transfer buffer has already been mapped. */
us->current_urb->transfer_flags =
URB_ASYNC_UNLINK | URB_NO_SETUP_DMA_MAP;
us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP;
if (us->current_urb->transfer_buffer == us->iobuf)
us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
us->current_urb->transfer_dma = us->iobuf_dma;
@ -611,7 +610,6 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
unsigned char old_sc_data_direction;
unsigned char old_cmd_len;
unsigned char old_cmnd[MAX_COMMAND_SIZE];
unsigned long old_serial_number;
int old_resid;
US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
@ -648,10 +646,6 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
old_sg = srb->use_sg;
srb->use_sg = 0;
/* change the serial number -- toggle the high bit*/
old_serial_number = srb->serial_number;
srb->serial_number ^= 0x80000000;
/* issue the auto-sense command */
old_resid = srb->resid;
srb->resid = 0;
@ -662,7 +656,6 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
srb->request_buffer = old_request_buffer;
srb->request_bufflen = old_request_bufflen;
srb->use_sg = old_sg;
srb->serial_number = old_serial_number;
srb->sc_data_direction = old_sc_data_direction;
srb->cmd_len = old_cmd_len;
memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
@ -985,7 +978,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(transfer_length);
bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
bcb->Tag = srb->serial_number;
bcb->Tag = ++us->tag;
bcb->Lun = srb->device->lun;
if (us->flags & US_FL_SCM_MULT_TARG)
bcb->Lun |= srb->device->id << 4;
@ -1074,7 +1067,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
le32_to_cpu(bcs->Signature), bcs->Tag,
residue, bcs->Status);
if (bcs->Tag != srb->serial_number || bcs->Status > US_BULK_STAT_PHASE) {
if (bcs->Tag != us->tag || bcs->Status > US_BULK_STAT_PHASE) {
US_DEBUGP("Bulk logical error\n");
return USB_STOR_TRANSPORT_ERROR;
}

View file

@ -79,6 +79,13 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0),
#endif
/* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */
UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003,
"VIA Technologies Inc.",
"USB 2.0 Card Reader",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
* Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
* always fails and confuses drive.
@ -929,6 +936,18 @@ UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
US_FL_SINGLE_LUN ),
#endif
/* Submitted by: Nick Sillik <n.sillik@temple.edu>
* Needed for OneTouch extension to usb-storage
*
*/
#ifdef CONFIG_USB_STORAGE_ONETOUCH
UNUSUAL_DEV( 0x0d49, 0x7010, 0x0000, 0x9999,
"Maxtor",
"OneTouch External Harddrive",
US_SC_DEVICE, US_PR_DEVICE, onetouch_connect_input,
0),
#endif
/* Submitted by Joris Struyve <joris@struyve.be> */
UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
"Medion",

View file

@ -90,7 +90,9 @@
#ifdef CONFIG_USB_STORAGE_JUMPSHOT
#include "jumpshot.h"
#endif
#ifdef CONFIG_USB_STORAGE_ONETOUCH
#include "onetouch.h"
#endif
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@ -786,6 +788,7 @@ static void usb_stor_release_resources(struct us_data *us)
* any more commands.
*/
US_DEBUGP("-- sending exit command to thread\n");
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
up(&us->sema);
/* Call the destructor routine, if it exists */
@ -816,6 +819,49 @@ static void dissociate_dev(struct us_data *us)
usb_set_intfdata(us->pusb_intf, NULL);
}
/* First stage of disconnect processing: stop all commands and remove
* the host */
static void quiesce_and_remove_host(struct us_data *us)
{
/* Prevent new USB transfers, stop the current command, and
* interrupt a SCSI-scan or device-reset delay */
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
usb_stor_stop_transport(us);
wake_up(&us->delay_wait);
/* It doesn't matter if the SCSI-scanning thread is still running.
* The thread will exit when it sees the DISCONNECTING flag. */
/* Wait for the current command to finish, then remove the host */
down(&us->dev_semaphore);
up(&us->dev_semaphore);
/* queuecommand won't accept any new commands and the control
* thread won't execute a previously-queued command. If there
* is such a command pending, complete it with an error. */
if (us->srb) {
us->srb->result = DID_NO_CONNECT << 16;
scsi_lock(us_to_host(us));
us->srb->scsi_done(us->srb);
us->srb = NULL;
scsi_unlock(us_to_host(us));
}
/* Now we own no commands so it's safe to remove the SCSI host */
scsi_remove_host(us_to_host(us));
}
/* Second stage of disconnect processing: deallocate all resources */
static void release_everything(struct us_data *us)
{
usb_stor_release_resources(us);
dissociate_dev(us);
/* Drop our reference to the host; the SCSI core will free it
* (and "us" along with it) when the refcount becomes 0. */
scsi_host_put(us_to_host(us));
}
/* Thread to carry out delayed SCSI-device scanning */
static int usb_stor_scan_thread(void * __us)
{
@ -956,7 +1002,7 @@ static int storage_probe(struct usb_interface *intf,
if (result < 0) {
printk(KERN_WARNING USB_STORAGE
"Unable to start the device-scanning thread\n");
scsi_remove_host(host);
quiesce_and_remove_host(us);
goto BadDevice;
}
atomic_inc(&total_threads);
@ -969,10 +1015,7 @@ static int storage_probe(struct usb_interface *intf,
/* We come here if there are any problems */
BadDevice:
US_DEBUGP("storage_probe() failed\n");
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
usb_stor_release_resources(us);
dissociate_dev(us);
scsi_host_put(host);
release_everything(us);
return result;
}
@ -982,28 +1025,8 @@ static void storage_disconnect(struct usb_interface *intf)
struct us_data *us = usb_get_intfdata(intf);
US_DEBUGP("storage_disconnect() called\n");
/* Prevent new USB transfers, stop the current command, and
* interrupt a SCSI-scan or device-reset delay */
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
usb_stor_stop_transport(us);
wake_up(&us->delay_wait);
/* It doesn't matter if the SCSI-scanning thread is still running.
* The thread will exit when it sees the DISCONNECTING flag. */
/* Wait for the current command to finish, then remove the host */
down(&us->dev_semaphore);
up(&us->dev_semaphore);
scsi_remove_host(us_to_host(us));
/* Wait for everything to become idle and release all our resources */
usb_stor_release_resources(us);
dissociate_dev(us);
/* Drop our reference to the host; the SCSI core will free it
* (and "us" along with it) when the refcount becomes 0. */
scsi_host_put(us_to_host(us));
quiesce_and_remove_host(us);
release_everything(us);
}
/***********************************************************************

View file

@ -158,6 +158,7 @@ struct us_data {
/* SCSI interfaces */
struct scsi_cmnd *srb; /* current srb */
unsigned int tag; /* current dCBWTag */
/* thread information */
int pid; /* control thread */

View file

@ -5,6 +5,7 @@
#include <linux/usb_ch9.h>
#define USB_MAJOR 180
#define USB_DEVICE_MAJOR 189
#ifdef __KERNEL__
@ -349,6 +350,7 @@ struct usb_device {
char *manufacturer;
char *serial; /* static strings from the device */
struct list_head filelist;
struct class_device *class_dev;
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
/*
@ -614,7 +616,6 @@ extern int usb_disabled(void);
#define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame ignored */
#define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */
#define URB_NO_SETUP_DMA_MAP 0x0008 /* urb->setup_dma valid on submit */
#define URB_ASYNC_UNLINK 0x0010 /* usb_unlink_urb() returns asap */
#define URB_NO_FSBR 0x0020 /* UHCI-specific */
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */
@ -722,13 +723,7 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
* Initialization:
*
* All URBs submitted must initialize the dev, pipe, transfer_flags (may be
* zero), and complete fields.
* The URB_ASYNC_UNLINK transfer flag affects later invocations of
* the usb_unlink_urb() routine. Note: Failure to set URB_ASYNC_UNLINK
* with usb_unlink_urb() is deprecated. For synchronous unlinks use
* usb_kill_urb() instead.
*
* All URBs must also initialize
* zero), and complete fields. All URBs must also initialize
* transfer_buffer and transfer_buffer_length. They may provide the
* URB_SHORT_NOT_OK transfer flag, indicating that short reads are
* to be treated as errors; that flag is invalid for write requests.

View file

@ -7,36 +7,18 @@
struct isp116x_platform_data {
/* Enable internal resistors on downstream ports */
unsigned sel15Kres:1;
/* Chip's internal clock won't be stopped in suspended state.
Setting/unsetting this bit takes effect only if
'remote_wakeup_enable' below is not set. */
unsigned clknotstop:1;
/* On-chip overcurrent protection */
/* On-chip overcurrent detection */
unsigned oc_enable:1;
/* INT output polarity */
unsigned int_act_high:1;
/* INT edge or level triggered */
unsigned int_edge_triggered:1;
/* WAKEUP pin connected - NOT SUPPORTED */
/* unsigned remote_wakeup_connected:1; */
/* Wakeup by devices on usb bus enabled */
/* Enable wakeup by devices on usb bus (e.g. wakeup
by attachment/detachment or by device activity
such as moving a mouse). When chosen, this option
prevents stopping internal clock, increasing
thereby power consumption in suspended state. */
unsigned remote_wakeup_enable:1;
/* Switch or not to switch (keep always powered) */
unsigned no_power_switching:1;
/* Ganged port power switching (0) or individual port
power switching (1) */
unsigned power_switching_mode:1;
/* Given port_power, msec/2 after power on till power good */
u8 potpg;
/* Hardware reset set/clear. If implemented, this function must:
if set == 0, deassert chip's HW reset pin
otherwise, assert chip's HW reset pin */
void (*reset) (struct device * dev, int set);
/* Hardware clock start/stop. If implemented, this function must:
if start == 0, stop the external clock
otherwise, start the external clock
*/
void (*clock) (struct device * dev, int start);
/* Inter-io delay (ns). The chip is picky about access timings; it
expects at least:
150ns delay between consecutive accesses to DATA_REG,

View file

@ -735,10 +735,9 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
if (test_bit(i, &subs->active_mask)) {
if (! test_and_set_bit(i, &subs->unlink_mask)) {
struct urb *u = subs->dataurb[i].urb;
if (async) {
u->transfer_flags |= URB_ASYNC_UNLINK;
if (async)
usb_unlink_urb(u);
} else
else
usb_kill_urb(u);
}
}
@ -748,10 +747,9 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
if (test_bit(i+16, &subs->active_mask)) {
if (! test_and_set_bit(i+16, &subs->unlink_mask)) {
struct urb *u = subs->syncurb[i].urb;
if (async) {
u->transfer_flags |= URB_ASYNC_UNLINK;
if (async)
usb_unlink_urb(u);
} else
else
usb_kill_urb(u);
}
}