diff options
80 files changed, 7406 insertions, 4076 deletions
diff --git a/Documentation/input/yealink.txt b/Documentation/input/yealink.txt new file mode 100644 index 00000000000..85f095a7ad0 --- /dev/null +++ b/Documentation/input/yealink.txt @@ -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. + diff --git a/MAINTAINERS b/MAINTAINERS index cb389067cf6..eaa46594f02 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/drivers/block/ub.c b/drivers/block/ub.c index a026567f5d1..aa0bf7ee008 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -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; + + } + + /* + * 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; } - cmd->data = rq->data; + 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; + } |