1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488 |
- /* $OpenBSD: pms.c,v 1.64 2015/07/20 00:55:06 kspillner Exp $ */
- /* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */
- /*-
- * Copyright (c) 1994 Charles M. Hannum.
- * Copyright (c) 1992, 1993 Erik Forsberg.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/rwlock.h>
- #include <sys/device.h>
- #include <sys/ioctl.h>
- #include <sys/malloc.h>
- #include <machine/bus.h>
- #include <dev/ic/pckbcvar.h>
- #include <dev/pckbc/pmsreg.h>
- #include <dev/wscons/wsconsio.h>
- #include <dev/wscons/wsmousevar.h>
- #if defined(__i386__) || defined(__amd64__)
- #include "acpi.h"
- #endif
- #if !defined(SMALL_KERNEL) && NACPI > 0
- extern int mouse_has_softbtn;
- #else
- int mouse_has_softbtn;
- #endif
- #ifdef DEBUG
- #define DPRINTF(x...) do { printf(x); } while (0);
- #else
- #define DPRINTF(x...)
- #endif
- #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
- #define WSMOUSE_BUTTON(x) (1 << ((x) - 1))
- struct pms_softc;
- struct pms_protocol {
- int type;
- #define PMS_STANDARD 0
- #define PMS_INTELLI 1
- #define PMS_SYNAPTICS 2
- #define PMS_ALPS 3
- #define PMS_ELANTECH_V1 4
- #define PMS_ELANTECH_V2 5
- #define PMS_ELANTECH_V3 6
- #define PMS_ELANTECH_V4 7
- u_int packetsize;
- int (*enable)(struct pms_softc *);
- int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *);
- int (*sync)(struct pms_softc *, int);
- void (*proc)(struct pms_softc *);
- void (*disable)(struct pms_softc *);
- };
- struct synaptics_softc {
- int identify;
- int capabilities, ext_capabilities, ext2_capabilities;
- int model, ext_model;
- int resolution, dimension;
- int modes;
- int mode;
- int mask;
- #define SYNAPTICS_MASK_NEWABS_STRICT 0xc8
- #define SYNAPTICS_MASK_NEWABS_RELAXED 0xc0
- #define SYNAPTICS_VALID_NEWABS_FIRST 0x80
- #define SYNAPTICS_VALID_NEWABS_NEXT 0xc0
- int res_x, res_y;
- int min_x, min_y;
- int max_x, max_y;
- /* Compat mode */
- int wsmode;
- int old_x, old_y;
- u_int old_buttons;
- u_int sec_buttons;
- #define SYNAPTICS_SCALE 4
- #define SYNAPTICS_PRESSURE 30
- };
- struct alps_softc {
- int model;
- #define ALPS_GLIDEPOINT (1 << 1)
- #define ALPS_DUALPOINT (1 << 2)
- #define ALPS_PASSTHROUGH (1 << 3)
- #define ALPS_INTERLEAVED (1 << 4)
- int mask;
- int version;
- int min_x, min_y;
- int max_x, max_y;
- int old_fin;
- u_int sec_buttons; /* trackpoint */
- /* Compat mode */
- int wsmode;
- int old_x, old_y;
- u_int old_buttons;
- #define ALPS_PRESSURE 40
- };
- struct elantech_softc {
- int flags;
- #define ELANTECH_F_REPORTS_PRESSURE 0x01
- #define ELANTECH_F_HAS_ROCKER 0x02
- #define ELANTECH_F_2FINGER_PACKET 0x04
- #define ELANTECH_F_HW_V1_OLD 0x08
- #define ELANTECH_F_CRC_ENABLED 0x10
- int fw_version;
- int min_x, min_y;
- int max_x, max_y;
- struct {
- unsigned int x;
- unsigned int y;
- unsigned int z;
- } mt[ELANTECH_MAX_FINGERS];
- int mt_slots;
- int mt_count;
- int mt_filter;
- int mt_lastid;
- int mt_lastcount;
- int mt_buttons;
- int width;
- u_char parity[256];
- u_char p1, p2, p3;
- /* Compat mode */
- int wsmode;
- int old_x, old_y;
- u_int old_buttons;
- };
- struct pms_softc { /* driver status information */
- struct device sc_dev;
- pckbc_tag_t sc_kbctag;
- int sc_state;
- #define PMS_STATE_DISABLED 0
- #define PMS_STATE_ENABLED 1
- #define PMS_STATE_SUSPENDED 2
- struct rwlock sc_state_lock;
- int sc_dev_enable;
- #define PMS_DEV_IGNORE 0x00
- #define PMS_DEV_PRIMARY 0x01
- #define PMS_DEV_SECONDARY 0x02
- int poll;
- int inputstate;
- const struct pms_protocol *protocol;
- struct synaptics_softc *synaptics;
- struct alps_softc *alps;
- struct elantech_softc *elantech;
- u_char packet[8];
- struct device *sc_wsmousedev;
- struct device *sc_sec_wsmousedev;
- };
- static const u_int butmap[8] = {
- 0,
- WSMOUSE_BUTTON(1),
- WSMOUSE_BUTTON(3),
- WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(3),
- WSMOUSE_BUTTON(2),
- WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2),
- WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3),
- WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3)
- };
- static const struct alps_model {
- int version;
- int mask;
- int model;
- } alps_models[] = {
- { 0x2021, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
- { 0x2221, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
- { 0x2222, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
- { 0x3222, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
- { 0x5212, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED },
- { 0x5321, 0xf8, ALPS_GLIDEPOINT },
- { 0x5322, 0xf8, ALPS_GLIDEPOINT },
- { 0x603b, 0xf8, ALPS_GLIDEPOINT },
- { 0x6222, 0xcf, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED },
- { 0x6321, 0xf8, ALPS_GLIDEPOINT },
- { 0x6322, 0xf8, ALPS_GLIDEPOINT },
- { 0x6323, 0xf8, ALPS_GLIDEPOINT },
- { 0x6324, 0x8f, ALPS_GLIDEPOINT },
- { 0x6325, 0xef, ALPS_GLIDEPOINT },
- { 0x6326, 0xf8, ALPS_GLIDEPOINT },
- { 0x7301, 0xf8, ALPS_DUALPOINT },
- { 0x7321, 0xf8, ALPS_GLIDEPOINT },
- { 0x7322, 0xf8, ALPS_GLIDEPOINT },
- { 0x7325, 0xcf, ALPS_GLIDEPOINT },
- #if 0
- /*
- * This model has a clitpad sending almost compatible PS2
- * packets but not compatible enough to be used with the
- * ALPS protocol.
- */
- { 0x633b, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
- { 0x7326, 0, 0 }, /* XXX Uses unknown v3 protocol */
- #endif
- };
- int pmsprobe(struct device *, void *, void *);
- void pmsattach(struct device *, struct device *, void *);
- int pmsactivate(struct device *, int);
- void pmsinput(void *, int);
- int pms_change_state(struct pms_softc *, int, int);
- int pms_ioctl(void *, u_long, caddr_t, int, struct proc *);
- int pms_enable(void *);
- void pms_disable(void *);
- int pms_sec_ioctl(void *, u_long, caddr_t, int, struct proc *);
- int pms_sec_enable(void *);
- void pms_sec_disable(void *);
- int pms_cmd(struct pms_softc *, u_char *, int, u_char *, int);
- int pms_spec_cmd(struct pms_softc *, int);
- int pms_get_devid(struct pms_softc *, u_char *);
- int pms_get_status(struct pms_softc *, u_char *);
- int pms_set_rate(struct pms_softc *, int);
- int pms_set_resolution(struct pms_softc *, int);
- int pms_set_scaling(struct pms_softc *, int);
- int pms_reset(struct pms_softc *);
- int pms_dev_enable(struct pms_softc *);
- int pms_dev_disable(struct pms_softc *);
- void pms_protocol_lookup(struct pms_softc *);
- int pms_enable_intelli(struct pms_softc *);
- int pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *);
- int pms_sync_mouse(struct pms_softc *, int);
- void pms_proc_mouse(struct pms_softc *);
- int pms_enable_synaptics(struct pms_softc *);
- int pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *);
- int pms_sync_synaptics(struct pms_softc *, int);
- void pms_proc_synaptics(struct pms_softc *);
- void pms_disable_synaptics(struct pms_softc *);
- int pms_enable_alps(struct pms_softc *);
- int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
- int pms_sync_alps(struct pms_softc *, int);
- void pms_proc_alps(struct pms_softc *);
- int pms_enable_elantech_v1(struct pms_softc *);
- int pms_enable_elantech_v2(struct pms_softc *);
- int pms_enable_elantech_v3(struct pms_softc *);
- int pms_enable_elantech_v4(struct pms_softc *);
- int pms_ioctl_elantech(struct pms_softc *, u_long, caddr_t, int,
- struct proc *);
- int pms_sync_elantech_v1(struct pms_softc *, int);
- int pms_sync_elantech_v2(struct pms_softc *, int);
- int pms_sync_elantech_v3(struct pms_softc *, int);
- int pms_sync_elantech_v4(struct pms_softc *, int);
- void pms_proc_elantech_v1(struct pms_softc *);
- void pms_proc_elantech_v2(struct pms_softc *);
- void pms_proc_elantech_v3(struct pms_softc *);
- void pms_proc_elantech_v4(struct pms_softc *);
- int synaptics_knock(struct pms_softc *);
- int synaptics_set_mode(struct pms_softc *, int);
- int synaptics_query(struct pms_softc *, int, int *);
- int synaptics_get_hwinfo(struct pms_softc *);
- void synaptics_sec_proc(struct pms_softc *);
- int alps_sec_proc(struct pms_softc *);
- int alps_get_hwinfo(struct pms_softc *);
- int elantech_knock(struct pms_softc *);
- void elantech_send_input(struct pms_softc *, int, int, int, int);
- int elantech_get_hwinfo_v1(struct pms_softc *);
- int elantech_get_hwinfo_v2(struct pms_softc *);
- int elantech_get_hwinfo_v3(struct pms_softc *);
- int elantech_get_hwinfo_v4(struct pms_softc *);
- int elantech_ps2_cmd(struct pms_softc *, u_char);
- int elantech_set_absolute_mode_v1(struct pms_softc *);
- int elantech_set_absolute_mode_v2(struct pms_softc *);
- int elantech_set_absolute_mode_v3(struct pms_softc *);
- int elantech_set_absolute_mode_v4(struct pms_softc *);
- void elantech_send_mt_input(struct pms_softc *, int);
- struct cfattach pms_ca = {
- sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
- pmsactivate
- };
- struct cfdriver pms_cd = {
- NULL, "pms", DV_DULL
- };
- const struct wsmouse_accessops pms_accessops = {
- pms_enable,
- pms_ioctl,
- pms_disable,
- };
- const struct wsmouse_accessops pms_sec_accessops = {
- pms_sec_enable,
- pms_sec_ioctl,
- pms_sec_disable,
- };
- const struct pms_protocol pms_protocols[] = {
- /* Generic PS/2 mouse */
- {
- PMS_STANDARD, 3,
- NULL,
- pms_ioctl_mouse,
- pms_sync_mouse,
- pms_proc_mouse,
- NULL
- },
- /* Synaptics touchpad */
- {
- PMS_SYNAPTICS, 6,
- pms_enable_synaptics,
- pms_ioctl_synaptics,
- pms_sync_synaptics,
- pms_proc_synaptics,
- pms_disable_synaptics
- },
- /* ALPS touchpad */
- {
- PMS_ALPS, 6,
- pms_enable_alps,
- pms_ioctl_alps,
- pms_sync_alps,
- pms_proc_alps,
- NULL
- },
- /* Elantech touchpad (hardware version 1) */
- {
- PMS_ELANTECH_V1, 4,
- pms_enable_elantech_v1,
- pms_ioctl_elantech,
- pms_sync_elantech_v1,
- pms_proc_elantech_v1,
- NULL
- },
- /* Elantech touchpad (hardware version 2) */
- {
- PMS_ELANTECH_V2, 6,
- pms_enable_elantech_v2,
- pms_ioctl_elantech,
- pms_sync_elantech_v2,
- pms_proc_elantech_v2,
- NULL
- },
- /* Elantech touchpad (hardware version 3) */
- {
- PMS_ELANTECH_V3, 6,
- pms_enable_elantech_v3,
- pms_ioctl_elantech,
- pms_sync_elantech_v3,
- pms_proc_elantech_v3,
- NULL
- },
- /* Elantech touchpad (hardware version 4) */
- {
- PMS_ELANTECH_V4, 6,
- pms_enable_elantech_v4,
- pms_ioctl_elantech,
- pms_sync_elantech_v4,
- pms_proc_elantech_v4,
- NULL
- },
- /* Microsoft IntelliMouse */
- {
- PMS_INTELLI, 4,
- pms_enable_intelli,
- pms_ioctl_mouse,
- pms_sync_mouse,
- pms_proc_mouse,
- NULL
- },
- };
- int
- pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen)
- {
- if (sc->poll) {
- return pckbc_poll_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT,
- cmd, len, resplen, resp, 1);
- } else {
- return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT,
- cmd, len, resplen, 1, resp);
- }
- }
- int
- pms_spec_cmd(struct pms_softc *sc, int cmd)
- {
- if (pms_set_scaling(sc, 1) ||
- pms_set_resolution(sc, (cmd >> 6) & 0x03) ||
- pms_set_resolution(sc, (cmd >> 4) & 0x03) ||
- pms_set_resolution(sc, (cmd >> 2) & 0x03) ||
- pms_set_resolution(sc, (cmd >> 0) & 0x03))
- return (-1);
- return (0);
- }
- int
- pms_get_devid(struct pms_softc *sc, u_char *resp)
- {
- u_char cmd[1];
- cmd[0] = PMS_SEND_DEV_ID;
- return (pms_cmd(sc, cmd, 1, resp, 1));
- }
- int
- pms_get_status(struct pms_softc *sc, u_char *resp)
- {
- u_char cmd[1];
- cmd[0] = PMS_SEND_DEV_STATUS;
- return (pms_cmd(sc, cmd, 1, resp, 3));
- }
- int
- pms_set_rate(struct pms_softc *sc, int value)
- {
- u_char cmd[2];
- cmd[0] = PMS_SET_SAMPLE;
- cmd[1] = value;
- return (pms_cmd(sc, cmd, 2, NULL, 0));
- }
- int
- pms_set_resolution(struct pms_softc *sc, int value)
- {
- u_char cmd[2];
- cmd[0] = PMS_SET_RES;
- cmd[1] = value;
- return (pms_cmd(sc, cmd, 2, NULL, 0));
- }
- int
- pms_set_scaling(struct pms_softc *sc, int scale)
- {
- u_char cmd[1];
- switch (scale) {
- case 1:
- default:
- cmd[0] = PMS_SET_SCALE11;
- break;
- case 2:
- cmd[0] = PMS_SET_SCALE21;
- break;
- }
- return (pms_cmd(sc, cmd, 1, NULL, 0));
- }
- int
- pms_reset(struct pms_softc *sc)
- {
- u_char cmd[1], resp[2];
- int res;
- cmd[0] = PMS_RESET;
- res = pms_cmd(sc, cmd, 1, resp, 2);
- #ifdef DEBUG
- if (res || resp[0] != PMS_RSTDONE || resp[1] != 0)
- printf("%s: reset error %d (response 0x%02x, type 0x%02x)\n",
- DEVNAME(sc), res, resp[0], resp[1]);
- #endif
- return (res);
- }
- int
- pms_dev_enable(struct pms_softc *sc)
- {
- u_char cmd[1];
- int res;
- cmd[0] = PMS_DEV_ENABLE;
- res = pms_cmd(sc, cmd, 1, NULL, 0);
- if (res)
- printf("%s: enable error\n", DEVNAME(sc));
- return (res);
- }
- int
- pms_dev_disable(struct pms_softc *sc)
- {
- u_char cmd[1];
- int res;
- cmd[0] = PMS_DEV_DISABLE;
- res = pms_cmd(sc, cmd, 1, NULL, 0);
- if (res)
- printf("%s: disable error\n", DEVNAME(sc));
- return (res);
- }
- void
- pms_protocol_lookup(struct pms_softc *sc)
- {
- int i;
- sc->protocol = &pms_protocols[0];
- for (i = 1; i < nitems(pms_protocols); i++) {
- pms_reset(sc);
- if (pms_protocols[i].enable(sc)) {
- sc->protocol = &pms_protocols[i];
- break;
- }
- }
- DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
- }
- int
- pms_enable_intelli(struct pms_softc *sc)
- {
- u_char resp;
- /* the special sequence to enable the third button and the roller */
- if (pms_set_rate(sc, PMS_INTELLI_MAGIC1) ||
- pms_set_rate(sc, PMS_INTELLI_MAGIC2) ||
- pms_set_rate(sc, PMS_INTELLI_MAGIC3) ||
- pms_get_devid(sc, &resp) ||
- resp != PMS_INTELLI_ID)
- return (0);
- return (1);
- }
- int
- pms_ioctl_mouse(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
- struct proc *p)
- {
- int i;
- switch (cmd) {
- case WSMOUSEIO_GTYPE:
- *(u_int *)data = WSMOUSE_TYPE_PS2;
- break;
- case WSMOUSEIO_SRES:
- i = ((int) *(u_int *)data - 12) / 25;
- /* valid values are {0,1,2,3} */
- if (i < 0)
- i = 0;
- if (i > 3)
- i = 3;
- if (pms_set_resolution(sc, i))
- printf("%s: SET_RES command error\n", DEVNAME(sc));
- break;
- default:
- return (-1);
- }
- return (0);
- }
- int
- pms_sync_mouse(struct pms_softc *sc, int data)
- {
- if (sc->inputstate != 0)
- return (0);
- switch (sc->protocol->type) {
- case PMS_STANDARD:
- if ((data & 0xc0) != 0)
- return (-1);
- break;
- case PMS_INTELLI:
- if ((data & 0x08) != 0x08)
- return (-1);
- break;
- }
- return (0);
- }
- void
- pms_proc_mouse(struct pms_softc *sc)
- {
- u_int buttons;
- int dx, dy, dz;
- buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK];
- dx = (sc->packet[0] & PMS_PS2_XNEG) ?
- (int)sc->packet[1] - 256 : sc->packet[1];
- dy = (sc->packet[0] & PMS_PS2_YNEG) ?
- (int)sc->packet[2] - 256 : sc->packet[2];
- if (sc->protocol->type == PMS_INTELLI)
- dz = (signed char)sc->packet[3];
- else
- dz = 0;
- wsmouse_input(sc->sc_wsmousedev,
- buttons, dx, dy, dz, 0, WSMOUSE_INPUT_DELTA);
- }
- int
- pmsprobe(struct device *parent, void *match, void *aux)
- {
- struct pckbc_attach_args *pa = aux;
- u_char cmd[1], resp[2];
- int res;
- if (pa->pa_slot != PCKBC_AUX_SLOT)
- return (0);
- /* Flush any garbage. */
- pckbc_flush(pa->pa_tag, pa->pa_slot);
- /* reset the device */
- cmd[0] = PMS_RESET;
- res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
- if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) {
- #ifdef DEBUG
- printf("pms: reset error %d (response 0x%02x, type 0x%02x)\n",
- res, resp[0], resp[1]);
- #endif
- return (0);
- }
- return (1);
- }
- void
- pmsattach(struct device *parent, struct device *self, void *aux)
- {
- struct pms_softc *sc = (void *)self;
- struct pckbc_attach_args *pa = aux;
- struct wsmousedev_attach_args a;
- sc->sc_kbctag = pa->pa_tag;
- pckbc_set_inputhandler(sc->sc_kbctag, PCKBC_AUX_SLOT,
- pmsinput, sc, DEVNAME(sc));
- printf("\n");
- a.accessops = &pms_accessops;
- a.accesscookie = sc;
- rw_init(&sc->sc_state_lock, "pmsst");
- /*
- * Attach the wsmouse, saving a handle to it.
- * Note that we don't need to check this pointer against NULL
- * here or in pmsintr, because if this fails pms_enable() will
- * never be called, so pmsinput() will never be called.
- */
- sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
- sc->poll = 1;
- sc->sc_dev_enable = 0;
- /* See if the device understands an extended (touchpad) protocol. */
- pms_protocol_lookup(sc);
- /* no interrupts until enabled */
- pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE);
- }
- int
- pmsactivate(struct device *self, int act)
- {
- struct pms_softc *sc = (struct pms_softc *)self;
- switch (act) {
- case DVACT_SUSPEND:
- if (sc->sc_state == PMS_STATE_ENABLED)
- pms_change_state(sc, PMS_STATE_SUSPENDED,
- PMS_DEV_IGNORE);
- break;
- case DVACT_RESUME:
- if (sc->sc_state == PMS_STATE_SUSPENDED)
- pms_change_state(sc, PMS_STATE_ENABLED,
- PMS_DEV_IGNORE);
- break;
- }
- return (0);
- }
- int
- pms_change_state(struct pms_softc *sc, int newstate, int dev)
- {
- if (dev != PMS_DEV_IGNORE) {
- switch (newstate) {
- case PMS_STATE_ENABLED:
- if (sc->sc_dev_enable & dev)
- return (EBUSY);
- sc->sc_dev_enable |= dev;
- if (sc->sc_state == PMS_STATE_ENABLED)
- return (0);
- break;
- case PMS_STATE_DISABLED:
- sc->sc_dev_enable &= ~dev;
- if (sc->sc_dev_enable)
- return (0);
- break;
- }
- }
- switch (newstate) {
- case PMS_STATE_ENABLED:
- sc->inputstate = 0;
- pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1);
- if (sc->poll)
- pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT);
- pms_reset(sc);
- if (sc->protocol->enable != NULL &&
- sc->protocol->enable(sc) == 0)
- pms_protocol_lookup(sc);
- pms_dev_enable(sc);
- break;
- case PMS_STATE_DISABLED:
- case PMS_STATE_SUSPENDED:
- pms_dev_disable(sc);
- if (sc->protocol->disable)
- sc->protocol->disable(sc);
- pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0);
- break;
- }
- sc->sc_state = newstate;
- sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0;
- return (0);
- }
- int
- pms_enable(void *v)
- {
- struct pms_softc *sc = v;
- int rv;
- rw_enter_write(&sc->sc_state_lock);
- rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
- rw_exit_write(&sc->sc_state_lock);
- return (rv);
- }
- void
- pms_disable(void *v)
- {
- struct pms_softc *sc = v;
- rw_enter_write(&sc->sc_state_lock);
- pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY);
- rw_exit_write(&sc->sc_state_lock);
- }
- int
- pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
- {
- struct pms_softc *sc = v;
- if (sc->protocol->ioctl)
- return (sc->protocol->ioctl(sc, cmd, data, flag, p));
- else
- return (-1);
- }
- int
- pms_sec_enable(void *v)
- {
- struct pms_softc *sc = v;
- int rv;
- rw_enter_write(&sc->sc_state_lock);
- rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY);
- rw_exit_write(&sc->sc_state_lock);
- return (rv);
- }
- void
- pms_sec_disable(void *v)
- {
- struct pms_softc *sc = v;
- rw_enter_write(&sc->sc_state_lock);
- pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY);
- rw_exit_write(&sc->sc_state_lock);
- }
- int
- pms_sec_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
- {
- switch (cmd) {
- case WSMOUSEIO_GTYPE:
- *(u_int *)data = WSMOUSE_TYPE_PS2;
- break;
- default:
- return (-1);
- }
- return (0);
- }
- void
- pmsinput(void *vsc, int data)
- {
- struct pms_softc *sc = vsc;
- if (sc->sc_state != PMS_STATE_ENABLED) {
- /* Interrupts are not expected. Discard the byte. */
- return;
- }
- sc->packet[sc->inputstate] = data;
- if (sc->protocol->sync(sc, data)) {
- #ifdef DIAGNOSTIC
- printf("%s: not in sync yet, discard input (state %d)\n",
- DEVNAME(sc), sc->inputstate);
- #endif
- sc->inputstate = 0;
- return;
- }
- sc->inputstate++;
- if (sc->inputstate != sc->protocol->packetsize)
- return;
- sc->inputstate = 0;
- sc->protocol->proc(sc);
- }
- int
- synaptics_set_mode(struct pms_softc *sc, int mode)
- {
- struct synaptics_softc *syn = sc->synaptics;
- if (pms_spec_cmd(sc, mode) ||
- pms_set_rate(sc, SYNAPTICS_CMD_SET_MODE))
- return (-1);
- syn->mode = mode;
- return (0);
- }
- int
- synaptics_query(struct pms_softc *sc, int query, int *val)
- {
- u_char resp[3];
- if (pms_spec_cmd(sc, query) ||
- pms_get_status(sc, resp))
- return (-1);
- if (val)
- *val = (resp[0] << 16) | (resp[1] << 8) | resp[2];
- return (0);
- }
- int
- synaptics_get_hwinfo(struct pms_softc *sc)
- {
- struct synaptics_softc *syn = sc->synaptics;
- if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY, &syn->identify))
- return (-1);
- if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES,
- &syn->capabilities))
- return (-1);
- if (synaptics_query(sc, SYNAPTICS_QUE_MODEL, &syn->model))
- return (-1);
- if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 1) &&
- synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL, &syn->ext_model))
- return (-1);
- if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 4) &&
- synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES,
- &syn->ext_capabilities))
- return (-1);
- if ((SYNAPTICS_ID_MAJOR(syn->identify) >= 4) &&
- synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION, &syn->resolution))
- return (-1);
- if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 5) &&
- (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_DIMENSIONS) &&
- synaptics_query(sc, SYNAPTICS_QUE_EXT_DIMENSIONS, &syn->dimension))
- return (-1);
- if (SYNAPTICS_ID_FULL(syn->identify) >= 0x705) {
- if (synaptics_query(sc, SYNAPTICS_QUE_MODES, &syn->modes))
- return (-1);
- if ((syn->modes & SYNAPTICS_EXT2_CAP) &&
- synaptics_query(sc, SYNAPTICS_QUE_EXT2_CAPABILITIES,
- &syn->ext2_capabilities))
- return (-1);
- }
- syn->res_x = SYNAPTICS_RESOLUTION_X(syn->resolution);
- syn->res_y = SYNAPTICS_RESOLUTION_Y(syn->resolution);
- syn->min_x = SYNAPTICS_XMIN_BEZEL;
- syn->min_y = SYNAPTICS_YMIN_BEZEL;
- syn->max_x = (syn->dimension) ?
- SYNAPTICS_DIM_X(syn->dimension) : SYNAPTICS_XMAX_BEZEL;
- syn->max_y = (syn->dimension) ?
- SYNAPTICS_DIM_Y(syn->dimension) : SYNAPTICS_YMAX_BEZEL;
- syn->sec_buttons = 0;
- if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) > 8)
- syn->ext_model &= ~0xf000;
- if ((syn->model & SYNAPTICS_MODEL_NEWABS) == 0) {
- printf("%s: don't support Synaptics OLDABS\n", DEVNAME(sc));
- return (-1);
- }
- if ((SYNAPTICS_ID_MAJOR(syn->identify) == 5) &&
- (SYNAPTICS_ID_MINOR(syn->identify) == 9))
- syn->mask = SYNAPTICS_MASK_NEWABS_RELAXED;
- else
- syn->mask = SYNAPTICS_MASK_NEWABS_STRICT;
- return (0);
- }
- void
- synaptics_sec_proc(struct pms_softc *sc)
- {
- struct synaptics_softc *syn = sc->synaptics;
- u_int buttons;
- int dx, dy;
- if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0)
- return;
- buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK];
- buttons |= syn->sec_buttons;
- dx = (sc->packet[1] & PMS_PS2_XNEG) ?
- (int)sc->packet[4] - 256 : sc->packet[4];
- dy = (sc->packet[1] & PMS_PS2_YNEG) ?
- (int)sc->packet[5] - 256 : sc->packet[5];
- wsmouse_input(sc->sc_sec_wsmousedev,
- buttons, dx, dy, 0, 0, WSMOUSE_INPUT_DELTA);
- }
- int
- synaptics_knock(struct pms_softc *sc)
- {
- u_char resp[3];
- if (pms_set_resolution(sc, 0) ||
- pms_set_resolution(sc, 0) ||
- pms_set_resolution(sc, 0) ||
- pms_set_resolution(sc, 0) ||
- pms_get_status(sc, resp) ||
- resp[1] != SYNAPTICS_ID_MAGIC)
- return (-1);
- return (0);
- }
- int
- pms_enable_synaptics(struct pms_softc *sc)
- {
- struct synaptics_softc *syn = sc->synaptics;
- struct wsmousedev_attach_args a;
- int mode, i;
- if (synaptics_knock(sc)) {
- if (sc->synaptics == NULL)
- goto err;
- /*
- * Some synaptics touchpads don't resume quickly.
- * Retry a few times.
- */
- for (i = 10; i > 0; --i) {
- printf("%s: device not resuming, retrying\n",
- DEVNAME(sc));
- pms_reset(sc);
- if (synaptics_knock(sc) == 0)
- break;
- delay(100000);
- }
- if (i == 0) {
- printf("%s: lost device\n", DEVNAME(sc));
- goto err;
- }
- }
- if (sc->synaptics == NULL) {
- sc->synaptics = syn = malloc(sizeof(struct synaptics_softc),
- M_DEVBUF, M_WAITOK | M_ZERO);
- if (syn == NULL) {
- printf("%s: synaptics: not enough memory\n",
- DEVNAME(sc));
- goto err;
- }
- if (synaptics_get_hwinfo(sc)) {
- free(sc->synaptics, M_DEVBUF, 0);
- sc->synaptics = NULL;
- goto err;
- }
- /* enable pass-through PS/2 port if supported */
- if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) {
- a.accessops = &pms_sec_accessops;
- a.accesscookie = sc;
- sc->sc_sec_wsmousedev = config_found((void *)sc, &a,
- wsmousedevprint);
- }
- syn->wsmode = WSMOUSE_COMPAT;
- printf("%s: Synaptics %s, firmware %d.%d\n", DEVNAME(sc),
- (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD ?
- "clickpad" : "touchpad"),
- SYNAPTICS_ID_MAJOR(syn->identify),
- SYNAPTICS_ID_MINOR(syn->identify));
- }
- mode = SYNAPTICS_ABSOLUTE_MODE | SYNAPTICS_HIGH_RATE;
- if (SYNAPTICS_ID_MAJOR(syn->identify) >= 4)
- mode |= SYNAPTICS_DISABLE_GESTURE;
- if (syn->capabilities & SYNAPTICS_CAP_EXTENDED)
- mode |= SYNAPTICS_W_MODE;
- if (synaptics_set_mode(sc, mode))
- goto err;
- /* enable advanced gesture mode if supported */
- if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) &&
- (pms_spec_cmd(sc, SYNAPTICS_QUE_MODEL) ||
- pms_set_rate(sc, SYNAPTICS_CMD_SET_ADV_GESTURE_MODE)))
- goto err;
- return (1);
- err:
- pms_reset(sc);
- return (0);
- }
- int
- pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
- struct proc *p)
- {
- struct synaptics_softc *syn = sc->synaptics;
- struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
- int wsmode;
- switch (cmd) {
- case WSMOUSEIO_GTYPE:
- if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) &&
- !(syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK)
- && mouse_has_softbtn)
- *(u_int *)data = WSMOUSE_TYPE_SYNAP_SBTN;
- else
- *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS;
- break;
- case WSMOUSEIO_GCALIBCOORDS:
- wsmc->minx = syn->min_x;
- wsmc->maxx = syn->max_x;
- wsmc->miny = syn->min_y;
- wsmc->maxy = syn->max_y;
- wsmc->swapxy = 0;
- wsmc->resx = syn->res_x;
- wsmc->resy = syn->res_y;
- break;
- case WSMOUSEIO_SETMODE:
- wsmode = *(u_int *)data;
- if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
- return (EINVAL);
- syn->wsmode = wsmode;
- break;
- default:
- return (-1);
- }
- return (0);
- }
- int
- pms_sync_synaptics(struct pms_softc *sc, int data)
- {
- struct synaptics_softc *syn = sc->synaptics;
- switch (sc->inputstate) {
- case 0:
- if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_FIRST)
- return (-1);
- break;
- case 3:
- if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_NEXT)
- return (-1);
- break;
- }
- return (0);
- }
- void
- pms_proc_synaptics(struct pms_softc *sc)
- {
- struct synaptics_softc *syn = sc->synaptics;
- u_int buttons;
- int x, y, z, w, dx, dy;
- w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) |
- ((sc->packet[3] & 0x04) >> 2);
- /*
- * Conform to the encoding understood by
- * /usr/xenocara/driver/xf86-input-synaptics/src/wsconscomm.c
- */
- switch (w) {
- case 0:
- /* fingerwidth 5, numfingers 2 */
- break;
- case 1:
- /* fingerwidth 5, numfingers 3 */
- break;
- case 5:
- /* fingerwidth 5, numfingers 1 */
- break;
- case 4:
- case 8:
- /* fingerwidth 4, numfingers 1 */
- w = 4;
- break;
- default:
- break;
- }
- if ((syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) && w == 3) {
- synaptics_sec_proc(sc);
- return;
- }
- if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0)
- return;
- /* XXX ignore advanced gesture packet, not yet supported */
- if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) && w == 2)
- return;
- x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) |
- sc->packet[4];
- y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) |
- sc->packet[5];
- z = sc->packet[2];
- buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ?
- WSMOUSE_BUTTON(1) : 0;
- buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ?
- WSMOUSE_BUTTON(3) : 0;
- if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) {
- buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
- WSMOUSE_BUTTON(1) : 0;
- } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON) {
- buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
- WSMOUSE_BUTTON(2) : 0;
- }
- if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON) {
- buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
- WSMOUSE_BUTTON(4) : 0;
- buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ?
- WSMOUSE_BUTTON(5) : 0;
- } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) &&
- ((sc->packet[0] ^ sc->packet[3]) & 0x02)) {
- if (syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) {
- /*
- * Trackstick buttons on this machine are wired to the
- * trackpad as extra buttons, so route the event
- * through the trackstick interface as normal buttons
- */
- syn->sec_buttons =
- (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(1) : 0;
- syn->sec_buttons |=
- (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(3) : 0;
- syn->sec_buttons |=
- (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(2) : 0;
- wsmouse_input(sc->sc_sec_wsmousedev,
- syn->sec_buttons, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
- return;
- }
- buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6) : 0;
- buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7) : 0;
- buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8) : 0;
- buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9) : 0;
- buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10) : 0;
- buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11) : 0;
- buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12) : 0;
- buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13) : 0;
- x &= ~0x0f;
- y &= ~0x0f;
- }
- /* ignore final events that happen when removing all fingers */
- if (x <= 1 || y <= 1) {
- x = syn->old_x;
- y = syn->old_y;
- }
- if (syn->wsmode == WSMOUSE_NATIVE) {
- wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, w,
- WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
- WSMOUSE_INPUT_ABSOLUTE_Z | WSMOUSE_INPUT_ABSOLUTE_W);
- } else {
- dx = dy = 0;
- if (z > SYNAPTICS_PRESSURE) {
- dx = x - syn->old_x;
- dy = y - syn->old_y;
- dx /= SYNAPTICS_SCALE;
- dy /= SYNAPTICS_SCALE;
- }
- if (dx || dy || buttons != syn->old_buttons)
- wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0,
- WSMOUSE_INPUT_DELTA);
- syn->old_buttons = buttons;
- }
- syn->old_x = x;
- syn->old_y = y;
- }
- void
- pms_disable_synaptics(struct pms_softc *sc)
- {
- struct synaptics_softc *syn = sc->synaptics;
- if (syn->capabilities & SYNAPTICS_CAP_SLEEP)
- synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE |
- SYNAPTICS_DISABLE_GESTURE);
- }
- int
- alps_sec_proc(struct pms_softc *sc)
- {
- struct alps_softc *alps = sc->alps;
- int dx, dy, pos = 0;
- if ((sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) {
- /*
- * We need to keep buttons states because interleaved
- * packets only signalize x/y movements.
- */
- alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK];
- } else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK) ==
- PMS_ALPS_INTERLEAVED_VALID) {
- sc->inputstate = 3;
- pos = 3;
- } else {
- return (0);
- }
- if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0)
- return (1);
- dx = (sc->packet[pos] & PMS_PS2_XNEG) ?
- (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1];
- dy = (sc->packet[pos] & PMS_PS2_YNEG) ?
- (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2];
- wsmouse_input(sc->sc_sec_wsmousedev, alps->sec_buttons,
- dx, dy, 0, 0, WSMOUSE_INPUT_DELTA);
- return (1);
- }
- int
- alps_get_hwinfo(struct pms_softc *sc)
- {
- struct alps_softc *alps = sc->alps;
- u_char resp[3];
- int i;
- if (pms_set_resolution(sc, 0) ||
- pms_set_scaling(sc, 2) ||
- pms_set_scaling(sc, 2) ||
- pms_set_scaling(sc, 2) ||
- pms_get_status(sc, resp)) {
- DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
- return (-1);
- }
- alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
- for (i = 0; i < nitems(alps_models); i++)
- if (alps->version == alps_models[i].version) {
- alps->model = alps_models[i].model;
- alps->mask = alps_models[i].mask;
- return (0);
- }
- return (-1);
- }
- int
- pms_enable_alps(struct pms_softc *sc)
- {
- struct alps_softc *alps = sc->alps;
- struct wsmousedev_attach_args a;
- u_char resp[3];
- if (pms_set_resolution(sc, 0) ||
- pms_set_scaling(sc, 1) ||
- pms_set_scaling(sc, 1) ||
- pms_set_scaling(sc, 1) ||
- pms_get_status(sc, resp) ||
- resp[0] != PMS_ALPS_MAGIC1 ||
- resp[1] != PMS_ALPS_MAGIC2 ||
- (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2 &&
- resp[2] != PMS_ALPS_MAGIC3_3))
- goto err;
- if (sc->alps == NULL) {
- sc->alps = alps = malloc(sizeof(struct alps_softc),
- M_DEVBUF, M_WAITOK | M_ZERO);
- if (alps == NULL) {
- printf("%s: alps: not enough memory\n", DEVNAME(sc));
- goto err;
- }
- if (alps_get_hwinfo(sc)) {
- free(sc->alps, M_DEVBUF, 0);
- sc->alps = NULL;
- goto err;
- }
- printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc),
- (alps->model & ALPS_DUALPOINT ? "Dualpoint" : "Glidepoint"),
- alps->version);
- alps->min_x = ALPS_XMIN_BEZEL;
- alps->min_y = ALPS_YMIN_BEZEL;
- alps->max_x = ALPS_XMAX_BEZEL;
- alps->max_y = ALPS_YMAX_BEZEL;
- alps->wsmode = WSMOUSE_COMPAT;
- if (alps->model & ALPS_DUALPOINT) {
- a.accessops = &pms_sec_accessops;
- a.accesscookie = sc;
- sc->sc_sec_wsmousedev = config_found((void *)sc, &a,
- wsmousedevprint);
- }
- }
- if (alps->model == 0)
- goto err;
- if ((alps->model & ALPS_PASSTHROUGH) &&
- (pms_set_scaling(sc, 2) ||
- pms_set_scaling(sc, 2) ||
- pms_set_scaling(sc, 2) ||
- pms_dev_disable(sc))) {
- DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
- goto err;
- }
- if (pms_dev_disable(sc) ||
- pms_dev_disable(sc) ||
- pms_set_rate(sc, 0x0a)) {
- DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
- goto err;
- }
- if (pms_dev_disable(sc) ||
- pms_dev_disable(sc) ||
- pms_dev_disable(sc) ||
- pms_dev_disable(sc) ||
- pms_dev_enable(sc)) {
- DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
- goto err;
- }
- if ((alps->model & ALPS_PASSTHROUGH) &&
- (pms_set_scaling(sc, 1) ||
- pms_set_scaling(sc, 1) ||
- pms_set_scaling(sc, 1) ||
- pms_dev_disable(sc))) {
- DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
- goto err;
- }
- alps->sec_buttons = 0;
- return (1);
- err:
- pms_reset(sc);
- return (0);
- }
- int
- pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
- struct proc *p)
- {
- struct alps_softc *alps = sc->alps;
- struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
- int wsmode;
- switch (cmd) {
- case WSMOUSEIO_GTYPE:
- *(u_int *)data = WSMOUSE_TYPE_ALPS;
- break;
- case WSMOUSEIO_GCALIBCOORDS:
- wsmc->minx = alps->min_x;
- wsmc->maxx = alps->max_x;
- wsmc->miny = alps->min_y;
- wsmc->maxy = alps->max_y;
- wsmc->swapxy = 0;
- break;
- case WSMOUSEIO_SETMODE:
- wsmode = *(u_int *)data;
- if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
- return (EINVAL);
- alps->wsmode = wsmode;
- break;
- default:
- return (-1);
- }
- return (0);
- }
- int
- pms_sync_alps(struct pms_softc *sc, int data)
- {
- struct alps_softc *alps = sc->alps;
- if ((alps->model & ALPS_DUALPOINT) &&
- (sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) {
- if (sc->inputstate == 2)
- sc->inputstate += 3;
- return (0);
- }
- switch (sc->inputstate) {
- case 0:
- if ((data & alps->mask) != alps->mask)
- return (-1);
- break;
- case 1:
- case 2:
- case 3:
- if ((data & PMS_ALPS_MASK) != PMS_ALPS_VALID)
- return (-1);
- break;
- case 4:
- case 5:
- if ((alps->model & ALPS_INTERLEAVED) == 0 &&
- (data & PMS_ALPS_MASK) != PMS_ALPS_VALID)
- return (-1);
- break;
- }
- return (0);
- }
- void
- pms_proc_alps(struct pms_softc *sc)
- {
- struct alps_softc *alps = sc->alps;
- int x, y, z, w, dx, dy;
- u_int buttons;
- int fin, ges;
- if ((alps->model & ALPS_DUALPOINT) && alps_sec_proc(sc))
- return;
- x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
- y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
- z = sc->packet[5];
- buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) |
- ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) |
- ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0);
- if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) && z == ALPS_Z_MAGIC) {
- dx = (x > ALPS_XSEC_BEZEL / 2) ? (x - ALPS_XSEC_BEZEL) : x;
- dy = (y > ALPS_YSEC_BEZEL / 2) ? (y - ALPS_YSEC_BEZEL) : y;
- wsmouse_input(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0,
- WSMOUSE_INPUT_DELTA);
- return;
- }
- if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0)
- return;
- /*
- * XXX The Y-axis is in the oposit direction compared to
- * Synaptics touchpads and PS/2 mouses.
- * It's why we need to translate the y value here for both
- * NATIVE and COMPAT modes.
- */
- y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL;
- if (alps->wsmode == WSMOUSE_NATIVE) {
- ges = sc->packet[2] & 0x01;
- fin = sc->packet[2] & 0x02;
- /* Simulate click (tap) */
- if (ges && !fin)
- z = 35;
- /* Generate a null pressure event (needed for tap & drag) */
- if (ges && fin && !alps->old_fin)
- z = 0;
- /* Generate a width value corresponding to one finger */
- if (z > 0)
- w = 4;
- else
- w = 0;
- wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, w,
- WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
- WSMOUSE_INPUT_ABSOLUTE_Z | WSMOUSE_INPUT_ABSOLUTE_W);
- alps->old_fin = fin;
- } else {
- dx = dy = 0;
- if (z > ALPS_PRESSURE) {
- dx = x - alps->old_x;
- dy = y - alps->old_y;
- /* Prevent jump */
- dx = abs(dx) > 50 ? 0 : dx;
- dy = abs(dy) > 50 ? 0 : dy;
- }
- if (dx || dy || buttons != alps->old_buttons)
- wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0,
- WSMOUSE_INPUT_DELTA);
- alps->old_x = x;
- alps->old_y = y;
- alps->old_buttons = buttons;
- }
- }
- int
- elantech_set_absolute_mode_v1(struct pms_softc *sc)
- {
- int i;
- u_char resp[3];
- /* Enable absolute mode. Magic numbers from Linux driver. */
- if (pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
- pms_spec_cmd(sc, 0x10) ||
- pms_spec_cmd(sc, 0x16) ||
- pms_set_scaling(sc, 1) ||
- pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
- pms_spec_cmd(sc, 0x11) ||
- pms_spec_cmd(sc, 0x8f) ||
- pms_set_scaling(sc, 1))
- return (-1);
- /* Read back reg 0x10 to ensure hardware is ready. */
- for (i = 0; i < 5; i++) {
- if (pms_spec_cmd(sc, ELANTECH_CMD_READ_REG) ||
- pms_spec_cmd(sc, 0x10) ||
- pms_get_status(sc, resp) == 0)
- break;
- delay(2000);
- }
- if (i == 5)
- return (-1);
- if ((resp[0] & ELANTECH_ABSOLUTE_MODE) == 0)
- return (-1);
- return (0);
- }
- int
- elantech_set_absolute_mode_v2(struct pms_softc *sc)
- {
- int i;
- u_char resp[3];
- u_char reg10 = (sc->elantech->fw_version == 0x20030 ? 0x54 : 0xc4);
- /* Enable absolute mode. Magic numbers from Linux driver. */
- if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x10) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, reg10) ||
- pms_set_scaling(sc, 1) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x11) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x88) ||
- pms_set_scaling(sc, 1))
- return (-1);
- /* Read back reg 0x10 to ensure hardware is ready. */
- for (i = 0; i < 5; i++) {
- if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, ELANTECH_CMD_READ_REG) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x10) ||
- pms_get_status(sc, resp) == 0)
- break;
- delay(2000);
- }
- if (i == 5)
- return (-1);
- return (0);
- }
- int
- elantech_set_absolute_mode_v3(struct pms_softc *sc)
- {
- int i;
- u_char resp[3];
- /* Enable absolute mode. Magic numbers from Linux driver. */
- if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x10) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x0b) ||
- pms_set_scaling(sc, 1))
- return (-1);
- /* Read back reg 0x10 to ensure hardware is ready. */
- for (i = 0; i < 5; i++) {
- if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x10) ||
- pms_get_status(sc, resp) == 0)
- break;
- delay(2000);
- }
- if (i == 5)
- return (-1);
- return (0);
- }
- int
- elantech_set_absolute_mode_v4(struct pms_softc *sc)
- {
- /* Enable absolute mode. Magic numbers from Linux driver. */
- if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x07) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
- elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
- elantech_ps2_cmd(sc, 0x01) ||
- pms_set_scaling(sc, 1))
- return (-1);
- /* v4 has no register 0x10 to read response from */
- return (0);
- }
- int
- elantech_get_hwinfo_v1(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- int fw_version;
- u_char capabilities[3];
- if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
- return (-1);
- if (fw_version < 0x20030 || fw_version == 0x20600) {
- if (fw_version < 0x20000)
- elantech->flags |= ELANTECH_F_HW_V1_OLD;
- } else
- return (-1);
- elantech->fw_version = fw_version;
- if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
- pms_get_status(sc, capabilities))
- return (-1);
- if (capabilities[0] & ELANTECH_CAP_HAS_ROCKER)
- elantech->flags |= ELANTECH_F_HAS_ROCKER;
- if (elantech_set_absolute_mode_v1(sc))
- return (-1);
- elantech->min_x = ELANTECH_V1_X_MIN;
- elantech->max_x = ELANTECH_V1_X_MAX;
- elantech->min_y = ELANTECH_V1_Y_MIN;
- elantech->max_y = ELANTECH_V1_Y_MAX;
- return (0);
- }
- int
- elantech_get_hwinfo_v2(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- int fw_version, ic_ver;
- u_char capabilities[3];
- int i, fixed_dpi;
- u_char resp[3];
- if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
- return (-1);
- ic_ver = (fw_version & 0x0f0000) >> 16;
- if (ic_ver != 2 && ic_ver != 4)
- return (-1);
- elantech->fw_version = fw_version;
- if (fw_version >= 0x20800)
- elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
- if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
- pms_get_status(sc, capabilities))
- return (-1);
- if (elantech_set_absolute_mode_v2(sc))
- return (-1);
- if (fw_version == 0x20800 || fw_version == 0x20b00 ||
- fw_version == 0x20030) {
- elantech->max_x = ELANTECH_V2_X_MAX;
- elantech->max_y = ELANTECH_V2_Y_MAX;
- } else {
- if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
- pms_get_status(sc, resp))
- return (-1);
- fixed_dpi = resp[1] & 0x10;
- i = (fw_version > 0x20800 && fw_version < 0x20900) ? 1 : 2;
- if ((fw_version >> 16) == 0x14 && fixed_dpi) {
- if (pms_spec_cmd(sc, ELANTECH_QUE_SAMPLE) ||
- pms_get_status(sc, resp))
- return (-1);
- elantech->max_x = (capabilities[1] - i) * resp[1] / 2;
- elantech->max_y = (capabilities[2] - i) * resp[2] / 2;
- } else if (fw_version == 0x040216) {
- elantech->max_x = 819;
- elantech->max_y = 405;
- } else if (fw_version == 0x040219 || fw_version == 0x040215) {
- elantech->max_x = 900;
- elantech->max_y = 500;
- } else {
- elantech->max_x = (capabilities[1] - i) * 64;
- elantech->max_y = (capabilities[2] - i) * 64;
- }
- }
- return (0);
- }
- int
- elantech_get_hwinfo_v3(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- int fw_version;
- u_char resp[3];
- if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
- return (-1);
- if (((fw_version & 0x0f0000) >> 16) != 5)
- return (-1);
- elantech->fw_version = fw_version;
- elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
- if ((fw_version & 0x4000) == 0x4000)
- elantech->flags |= ELANTECH_F_CRC_ENABLED;
- if (elantech_set_absolute_mode_v3(sc))
- return (-1);
- if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
- pms_get_status(sc, resp))
- return (-1);
- elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1];
- elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2];
- return (0);
- }
- int
- elantech_get_hwinfo_v4(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- int fw_version;
- u_char capabilities[3];
- u_char resp[3];
- if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
- return (-1);
- if (((fw_version & 0x0f0000) >> 16) != 6 &&
- (fw_version & 0x0f0000) >> 16 != 8)
- return (-1);
- elantech->fw_version = fw_version;
- elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
- if (elantech_set_absolute_mode_v4(sc))
- return (-1);
- if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
- pms_get_status(sc, capabilities))
- return (-1);
- if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
- pms_get_status(sc, resp))
- return (-1);
- elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1];
- elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2];
- if ((capabilities[1] < 2) || (capabilities[1] > elantech->max_x))
- return (-1);
- elantech->width = elantech->max_x / (capabilities[1] - 1);
- return (0);
- }
- int
- elantech_ps2_cmd(struct pms_softc *sc, u_char command)
- {
- u_char cmd[1];
- cmd[0] = command;
- return (pms_cmd(sc, cmd, 1, NULL, 0));
- }
- int
- elantech_knock(struct pms_softc *sc)
- {
- u_char resp[3];
- if (pms_dev_disable(sc) ||
- pms_set_scaling(sc, 1) ||
- pms_set_scaling(sc, 1) ||
- pms_set_scaling(sc, 1) ||
- pms_get_status(sc, resp) ||
- resp[0] != PMS_ELANTECH_MAGIC1 ||
- resp[1] != PMS_ELANTECH_MAGIC2 ||
- (resp[2] != PMS_ELANTECH_MAGIC3_1 &&
- resp[2] != PMS_ELANTECH_MAGIC3_2))
- return (-1);
- return (0);
- }
- int
- pms_enable_elantech_v1(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- int i;
- if (elantech_knock(sc))
- goto err;
- if (sc->elantech == NULL) {
- sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
- M_DEVBUF, M_WAITOK | M_ZERO);
- if (elantech == NULL) {
- printf("%s: elantech: not enough memory\n",
- DEVNAME(sc));
- goto err;
- }
- if (elantech_get_hwinfo_v1(sc)) {
- free(sc->elantech, M_DEVBUF, 0);
- sc->elantech = NULL;
- goto err;
- }
- printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
- DEVNAME(sc), 1, sc->elantech->fw_version);
- } else if (elantech_set_absolute_mode_v1(sc))
- goto err;
- for (i = 0; i < nitems(sc->elantech->parity); i++)
- sc->elantech->parity[i] = sc->elantech->parity[i & (i - 1)] ^ 1;
- return (1);
- err:
- pms_reset(sc);
- return (0);
- }
- int
- pms_enable_elantech_v2(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- if (elantech_knock(sc))
- goto err;
- if (sc->elantech == NULL) {
- sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
- M_DEVBUF, M_WAITOK | M_ZERO);
- if (elantech == NULL) {
- printf("%s: elantech: not enough memory\n",
- DEVNAME(sc));
- goto err;
- }
- if (elantech_get_hwinfo_v2(sc)) {
- free(sc->elantech, M_DEVBUF, 0);
- sc->elantech = NULL;
- goto err;
- }
- printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
- DEVNAME(sc), 2, sc->elantech->fw_version);
- } else if (elantech_set_absolute_mode_v2(sc))
- goto err;
- return (1);
- err:
- pms_reset(sc);
- return (0);
- }
- int
- pms_enable_elantech_v3(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- if (elantech_knock(sc))
- goto err;
- if (sc->elantech == NULL) {
- sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
- M_DEVBUF, M_WAITOK | M_ZERO);
- if (elantech == NULL) {
- printf("%s: elantech: not enough memory\n",
- DEVNAME(sc));
- goto err;
- }
- if (elantech_get_hwinfo_v3(sc)) {
- free(sc->elantech, M_DEVBUF, 0);
- sc->elantech = NULL;
- goto err;
- }
- printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
- DEVNAME(sc), 3, sc->elantech->fw_version);
- } else if (elantech_set_absolute_mode_v3(sc))
- goto err;
- return (1);
- err:
- pms_reset(sc);
- return (0);
- }
- int
- pms_enable_elantech_v4(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- if (elantech_knock(sc))
- goto err;
- if (sc->elantech == NULL) {
- sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
- M_DEVBUF, M_WAITOK | M_ZERO);
- if (elantech == NULL) {
- printf("%s: elantech: not enough memory\n",
- DEVNAME(sc));
- goto err;
- }
- if (elantech_get_hwinfo_v4(sc)) {
- free(sc->elantech, M_DEVBUF, 0);
- sc->elantech = NULL;
- goto err;
- }
- printf("%s: Elantech Clickpad, version %d, firmware 0x%x\n",
- DEVNAME(sc), 4, sc->elantech->fw_version);
- } else if (elantech_set_absolute_mode_v4(sc))
- goto err;
- return (1);
- err:
- pms_reset(sc);
- return (0);
- }
- int
- pms_ioctl_elantech(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
- struct proc *p)
- {
- struct elantech_softc *elantech = sc->elantech;
- struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
- int wsmode;
- switch (cmd) {
- case WSMOUSEIO_GTYPE:
- *(u_int *)data = WSMOUSE_TYPE_ELANTECH;
- break;
- case WSMOUSEIO_GCALIBCOORDS:
- wsmc->minx = elantech->min_x;
- wsmc->maxx = elantech->max_x;
- wsmc->miny = elantech->min_y;
- wsmc->maxy = elantech->max_y;
- wsmc->swapxy = 0;
- wsmc->resx = 0;
- wsmc->resy = 0;
- break;
- case WSMOUSEIO_SETMODE:
- wsmode = *(u_int *)data;
- if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
- return (EINVAL);
- elantech->wsmode = wsmode;
- break;
- default:
- return (-1);
- }
- return (0);
- }
- int
- pms_sync_elantech_v1(struct pms_softc *sc, int data)
- {
- struct elantech_softc *elantech = sc->elantech;
- u_char p;
- switch (sc->inputstate) {
- case 0:
- if (elantech->flags & ELANTECH_F_HW_V1_OLD) {
- elantech->p1 = (data & 0x20) >> 5;
- elantech->p2 = (data & 0x10) >> 4;
- } else {
- elantech->p1 = (data & 0x10) >> 4;
- elantech->p2 = (data & 0x20) >> 5;
- }
- elantech->p3 = (data & 0x04) >> 2;
- return (0);
- case 1:
- p = elantech->p1;
- break;
- case 2:
- p = elantech->p2;
- break;
- case 3:
- p = elantech->p3;
- break;
- default:
- return (-1);
- }
- if (data < 0 || data >= nitems(elantech->parity) ||
- elantech->parity[data] != p)
- return (-1);
- return (0);
- }
- int
- pms_sync_elantech_v2(struct pms_softc *sc, int data)
- {
- struct elantech_softc *elantech = sc->elantech;
- /* Variants reporting pressure always have the same constant bits. */
- if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) {
- if (sc->inputstate == 0 && (data & 0x0c) != 0x04)
- return (-1);
- if (sc->inputstate == 3 && (data & 0x0f) != 0x02)
- return (-1);
- return (0);
- }
- /* For variants not reporting pressure, 1 and 3 finger touch packets
- * have different constant bits than 2 finger touch pakets. */
- switch (sc->inputstate) {
- case 0:
- if ((data & 0xc0) == 0x80) {
- if ((data & 0x0c) != 0x0c)
- return (-1);
- elantech->flags |= ELANTECH_F_2FINGER_PACKET;
- } else {
- if ((data & 0x3c) != 0x3c)
- return (-1);
- elantech->flags &= ~ELANTECH_F_2FINGER_PACKET;
- }
- break;
- case 1:
- case 4:
- if (elantech->flags & ELANTECH_F_2FINGER_PACKET)
- break;
- if ((data & 0xf0) != 0x00)
- return (-1);
- break;
- case 3:
- if (elantech->flags & ELANTECH_F_2FINGER_PACKET) {
- if ((data & 0x0e) != 0x08)
- return (-1);
- } else {
- if ((data & 0x3e) != 0x38)
- return (-1);
- }
- break;
- default:
- break;
- }
- return (0);
- }
- int
- pms_sync_elantech_v3(struct pms_softc *sc, int data)
- {
- struct elantech_softc *elantech = sc->elantech;
- switch (sc->inputstate) {
- case 0:
- if (elantech->flags & ELANTECH_F_CRC_ENABLED)
- break;
- if ((data & 0x0c) != 0x04 && (data & 0x0c) != 0x0c)
- return (-1);
- break;
- case 3:
- if (elantech->flags & ELANTECH_F_CRC_ENABLED) {
- if ((data & 0x09) != 0x08 && (data & 0x09) != 0x09)
- return (-1);
- } else {
- if ((data & 0xcf) != 0x02 && (data & 0xce) != 0x0c)
- return (-1);
- }
- break;
- }
- return (0);
- }
- int
- pms_sync_elantech_v4(struct pms_softc *sc, int data)
- {
- if (sc->inputstate == 0 && (data & 0x0c) != 0x04)
- return (-1);
- else
- return (0);
- }
- void
- pms_proc_elantech_v1(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- int x, y, w, z;
- if (elantech->flags & ELANTECH_F_HW_V1_OLD)
- w = ((sc->packet[1] & 0x80) >> 7) +
- ((sc->packet[1] & 0x30) >> 4);
- else
- w = (sc->packet[0] & 0xc0) >> 6;
- /* Hardware version 1 doesn't report pressure. */
- if (w) {
- x = ((sc->packet[1] & 0x0c) << 6) | sc->packet[2];
- y = ((sc->packet[1] & 0x03) << 8) | sc->packet[3];
- z = SYNAPTICS_PRESSURE;
- } else {
- x = elantech->old_x;
- y = elantech->old_y;
- z = 0;
- }
- elantech_send_input(sc, x, y, z, w);
- }
- void
- pms_proc_elantech_v2(struct pms_softc *sc)
- {
- const u_char debounce_pkt[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff };
- struct elantech_softc *elantech = sc->elantech;
- int x, y, w, z;
- /*
- * The hardware sends this packet when in debounce state.
- * The packet should be ignored.
- */
- if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt)))
- return;
- w = (sc->packet[0] & 0xc0) >> 6;
- if (w == 1 || w == 3) {
- x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
- y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
- if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE)
- z = ((sc->packet[1] & 0xf0) |
- (sc->packet[4] & 0xf0) >> 4);
- else
- z = SYNAPTICS_PRESSURE;
- } else if (w == 2) {
- x = (((sc->packet[0] & 0x10) << 4) | sc->packet[1]) << 2;
- y = (((sc->packet[0] & 0x20) << 3) | sc->packet[2]) << 2;
- z = SYNAPTICS_PRESSURE;
- } else {
- x = elantech->old_x;
- y = elantech->old_y;
- z = 0;
- }
- elantech_send_input(sc, x, y, z, w);
- }
- void
- pms_proc_elantech_v3(struct pms_softc *sc)
- {
- const u_char debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
- struct elantech_softc *elantech = sc->elantech;
- int x, y, w, z;
- x = ((sc->packet[1] & 0x0f) << 8 | sc->packet[2]);
- y = ((sc->packet[4] & 0x0f) << 8 | sc->packet[5]);
- z = 0;
- w = (sc->packet[0] & 0xc0) >> 6;
- if (w == 2) {
- /*
- * Two-finger touch causes two packets -- a head packet
- * and a tail packet. We report a single event and ignore
- * the tail packet.
- */
- if (elantech->flags & ELANTECH_F_CRC_ENABLED) {
- if ((sc->packet[3] & 0x09) != 0x08)
- return;
- } else {
- /* The hardware sends this packet when in debounce state.
- * The packet should be ignored. */
- if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt)))
- return;
- if ((sc->packet[0] & 0x0c) != 0x04 &&
- (sc->packet[3] & 0xcf) != 0x02) {
- /* not the head packet -- ignore */
- return;
- }
- }
- }
- /* Prevent juming cursor if pad isn't touched or reports garbage. */
- if (w == 0 ||
- ((x == 0 || y == 0 || x == elantech->max_x || y == elantech->max_y)
- && (x != elantech->old_x || y != elantech->old_y))) {
- x = elantech->old_x;
- y = elantech->old_y;
- }
- if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE)
- z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4);
- else if (w)
- z = SYNAPTICS_PRESSURE;
- elantech_send_input(sc, x, y, z, w);
- }
- void
- pms_proc_elantech_v4(struct pms_softc *sc)
- {
- struct elantech_softc *elantech = sc->elantech;
- int n, id, slots, weight, dx, dy;
- switch (sc->packet[3] & 0x1f) {
- case ELANTECH_V4_PKT_STATUS:
- if (elantech->mt_slots == 0)
- elantech->mt_lastid = -1;
- slots = sc->packet[1] & 0x1f;
- if (slots == 0 && elantech->mt_lastid > -1)
- /* Notify that we lifted. */
- elantech_send_input(sc,
- elantech->mt[elantech->mt_lastid].x,
- elantech->mt[elantech->mt_lastid].y, 0, 0);
- elantech->mt_filter = elantech->mt_slots = slots;
- for (elantech->mt_count = 0; slots != 0; slots >>= 1)
- elantech->mt_count += (1 & slots);
- break;
- case ELANTECH_V4_PKT_HEAD:
- id = ((sc->packet[3] & 0xe0) >> 5) - 1;
- if (id > -1 && id < ELANTECH_MAX_FINGERS) {
- elantech->mt[id].x =
- ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
- elantech->mt[id].y =
- ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
- elantech->mt[id].z =
- (sc->packet[1] & 0xf0)
- | ((sc->packet[4] & 0xf0) >> 4);
- if (elantech->mt_filter & (1 << id)) {
- elantech_send_mt_input(sc, id);
- elantech->mt_filter = (1 << id);
- }
- }
- break;
- case ELANTECH_V4_PKT_MOTION:
- weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE : 1;
- for (n = 0; n < 6; n += 3) {
- id = ((sc->packet[n] & 0xe0) >> 5) - 1;
- if (id < 0 || id >= ELANTECH_MAX_FINGERS)
- continue;
- dx = weight * (signed char)sc->packet[n + 1];
- dy = weight * (signed char)sc->packet[n + 2];
- elantech->mt[id].x += dx;
- elantech->mt[id].y += dy;
- elantech->mt[id].z = 1;
- if (elantech->mt_filter & (1 << id)) {
- if ((dx | dy)
- || elantech->mt_count !=
- elantech->mt_lastcount
- || (sc->packet[0] & 3) !=
- elantech->mt_buttons)
- elantech_send_mt_input(sc, id);
- elantech->mt_filter = (dx | dy) ?
- (1 << id) : elantech->mt_slots;
- }
- }
- break;
- default:
- printf("%s: unknown packet type 0x%x\n", DEVNAME(sc),
- sc->packet[3] & 0x1f);
- return;
- }
- }
- void
- elantech_send_mt_input(struct pms_softc *sc, int id)
- {
- struct elantech_softc *elantech = sc->elantech;
- if (id != elantech->mt_lastid) {
- /* Correct for compatibility mode, but not useful yet: */
- elantech->old_x = elantech->mt[id].x;
- elantech->old_y = elantech->mt[id].y;
- /*
- * To avoid a jump of the cursor, simulate a change of the
- * number of touches (without producing tapping gestures
- * accidentally). It should suffice to do that only if
- * mt_count hasn't changed, but we cannot rely on the
- * synaptics driver, which alters its finger counts when
- * handling click-and-drag actions (see HandleTapProcessing
- * and ComputeDeltas in synaptics.c).
- */
- if (elantech->mt_lastid > -1)
- elantech_send_input(sc,
- elantech->mt[id].x, elantech->mt[id].y,
- elantech->mt[id].z, ELANTECH_MAX_FINGERS);
- elantech->mt_lastid = id;
- }
- elantech->mt_lastcount = elantech->mt_count;
- elantech->mt_buttons = sc->packet[0] & 3;
- elantech_send_input(sc,
- elantech->mt[id].x, elantech->mt[id].y,
- elantech->mt[id].z, elantech->mt_count);
- }
- void
- elantech_send_input(struct pms_softc *sc, int x, int y, int z, int w)
- {
- struct elantech_softc *elantech = sc->elantech;
- int dx, dy;
- u_int buttons = 0;
- if (sc->packet[0] & 0x01)
- buttons |= WSMOUSE_BUTTON(1);
- if (sc->packet[0] & 0x02)
- buttons |= WSMOUSE_BUTTON(3);
- if (elantech->flags & ELANTECH_F_HAS_ROCKER) {
- if (sc->packet[0] & 0x40) /* up */
- buttons |= WSMOUSE_BUTTON(4);
- if (sc->packet[0] & 0x80) /* down */
- buttons |= WSMOUSE_BUTTON(5);
- }
- if (elantech->wsmode == WSMOUSE_NATIVE) {
- wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, w,
- WSMOUSE_INPUT_ABSOLUTE_X |
- WSMOUSE_INPUT_ABSOLUTE_Y |
- WSMOUSE_INPUT_ABSOLUTE_Z |
- WSMOUSE_INPUT_ABSOLUTE_W);
- } else {
- dx = dy = 0;
- if ((elantech->flags & ELANTECH_F_REPORTS_PRESSURE) &&
- z > SYNAPTICS_PRESSURE) {
- dx = x - elantech->old_x;
- dy = y - elantech->old_y;
- dx /= SYNAPTICS_SCALE;
- dy /= SYNAPTICS_SCALE;
- }
- if (dx || dy || buttons != elantech->old_buttons)
- wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0,
- WSMOUSE_INPUT_DELTA);
- elantech->old_buttons = buttons;
- }
- elantech->old_x = x;
- elantech->old_y = y;
- }
|