diff options
| author | Henrik Rydberg <rydberg@euromail.se> | 2008-10-08 23:28:07 +0200 |
|---|---|---|
| committer | Henrik Rydberg <rydberg@euromail.se> | 2008-10-08 23:28:07 +0200 |
| commit | 5b36c0f3cbbf29ab25038b1af3b158262d527116 (patch) | |
| tree | 04552202749379c75991dd8c2536dc058766e38f | |
| parent | fdf8de5f419e66a793e64896c53f0ccff0a19efb (diff) | |
bcm5974 (0.58) unstable; urgency=low
* Name changes; use usbhid definitions, rename atp to bcm5974
* Input syncing moved to report functions, event type setup broken out
* Traffic functions added for open/close and suspend/resume logic
* Open/close and suspend/resume transition logic corrected
* Open/close serialized with respect to suspend/resume
-- Henrik Rydberg <rydberg@euromail.se> Wed, 23 Jul 2008 02:20:10 +0200
| -rw-r--r-- | CHANGES | 12 | ||||
| -rw-r--r-- | bcm5974-dkms-mkdeb/debian/changelog | 7 | ||||
| -rw-r--r-- | bcm5974.c | 392 | ||||
| -rw-r--r-- | dkms.conf | 2 |
4 files changed, 226 insertions, 187 deletions
| @@ -1,9 +1,19 @@ | |||
| 1 | bcm5974 (0.58) unstable; urgency=low | ||
| 2 | |||
| 3 | * Name changes; use usbhid definitions, rename atp to bcm5974 | ||
| 4 | * Input syncing moved to report functions, event type setup broken out | ||
| 5 | * Traffic functions added for open/close and suspend/resume logic | ||
| 6 | * Open/close and suspend/resume transition logic corrected | ||
| 7 | * Open/close serialized with respect to suspend/resume | ||
| 8 | |||
| 9 | -- Henrik Rydberg <rydberg@euromail.se> Wed, 23 Jul 2008 02:20:10 +0200 | ||
| 10 | |||
| 1 | bcm5974 (0.57) unstable; urgency=low | 11 | bcm5974 (0.57) unstable; urgency=low |
| 2 | 12 | ||
| 3 | * Keep reset_resume around | 13 | * Keep reset_resume around |
| 4 | * Submitted to kernel.org | 14 | * Submitted to kernel.org |
| 5 | 15 | ||
| 6 | -- Henrik Rydberg <rydberg@euromail.se> Fri, 18 Jul 2008 02:42:52 +0200 | 16 | -- Henrik Rydberg <rydberg@euromail.se> Sat, 19 Jul 2008 01:42:52 +0200 |
| 7 | 17 | ||
| 8 | bcm5974 (0.56) unstable; urgency=low | 18 | bcm5974 (0.56) unstable; urgency=low |
| 9 | 19 | ||
diff --git a/bcm5974-dkms-mkdeb/debian/changelog b/bcm5974-dkms-mkdeb/debian/changelog index 76304fd..b0211af 100644 --- a/bcm5974-dkms-mkdeb/debian/changelog +++ b/bcm5974-dkms-mkdeb/debian/changelog | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | MODULE_NAME-dkms (MODULE_VERSION) unstable; urgency=low | 1 | MODULE_NAME-dkms (MODULE_VERSION) unstable; urgency=low |
| 2 | 2 | ||
| 3 | * Keep reset_resume around | 3 | * Name changes; use usbhid definitions, rename atp to bcm5974 |
| 4 | * Submitted to kernel.org | 4 | * Input syncing moved to report functions, event type setup broken out |
| 5 | * Traffic functions added for open/close and suspend/resume logic | ||
| 6 | * Open/close and suspend/resume transition logic corrected | ||
| 7 | * Open/close serialized with respect to suspend/resume | ||
| 5 | 8 | ||
| 6 | -- Henrik Rydberg <rydberg@euromail.se> DATE_STAMP | 9 | -- Henrik Rydberg <rydberg@euromail.se> DATE_STAMP |
| @@ -39,42 +39,43 @@ | |||
| 39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
| 40 | #include <linux/usb/input.h> | 40 | #include <linux/usb/input.h> |
| 41 | #include <linux/hid.h> | 41 | #include <linux/hid.h> |
| 42 | #include <linux/mutex.h> | ||
| 42 | 43 | ||
| 43 | #define APPLE_VENDOR_ID 0x05AC | 44 | #define USB_VENDOR_ID_APPLE 0x05ac |
| 44 | 45 | ||
| 45 | /* MacbookAir, aka wellspring */ | 46 | /* MacbookAir, aka wellspring */ |
| 46 | #define ATP_WELLSPRING_ANSI 0x0223 | 47 | #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 |
| 47 | #define ATP_WELLSPRING_ISO 0x0224 | 48 | #define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224 |
| 48 | #define ATP_WELLSPRING_JIS 0x0225 | 49 | #define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225 |
| 49 | /* MacbookProPenryn, aka wellspring2 */ | 50 | /* MacbookProPenryn, aka wellspring2 */ |
| 50 | #define ATP_WELLSPRING2_ANSI 0x0230 | 51 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 |
| 51 | #define ATP_WELLSPRING2_ISO 0x0231 | 52 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 |
| 52 | #define ATP_WELLSPRING2_JIS 0x0232 | 53 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 |
| 53 | 54 | ||
| 54 | #define ATP_DEVICE(prod) { \ | 55 | #define BCM5974_DEVICE(prod) { \ |
| 55 | .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ | 56 | .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ |
| 56 | USB_DEVICE_ID_MATCH_INT_CLASS | \ | 57 | USB_DEVICE_ID_MATCH_INT_CLASS | \ |
| 57 | USB_DEVICE_ID_MATCH_INT_PROTOCOL), \ | 58 | USB_DEVICE_ID_MATCH_INT_PROTOCOL), \ |
| 58 | .idVendor = APPLE_VENDOR_ID, \ | 59 | .idVendor = USB_VENDOR_ID_APPLE, \ |
| 59 | .idProduct = (prod), \ | 60 | .idProduct = (prod), \ |
| 60 | .bInterfaceClass = USB_INTERFACE_CLASS_HID, \ | 61 | .bInterfaceClass = USB_INTERFACE_CLASS_HID, \ |
| 61 | .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE \ | 62 | .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE \ |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | /* table of devices that work with this driver */ | 65 | /* table of devices that work with this driver */ |
| 65 | static const struct usb_device_id atp_table [] = { | 66 | static const struct usb_device_id bcm5974_table [] = { |
| 66 | /* MacbookAir1.1 */ | 67 | /* MacbookAir1.1 */ |
| 67 | ATP_DEVICE(ATP_WELLSPRING_ANSI), | 68 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), |
| 68 | ATP_DEVICE(ATP_WELLSPRING_ISO), | 69 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO), |
| 69 | ATP_DEVICE(ATP_WELLSPRING_JIS), | 70 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_JIS), |
| 70 | /* MacbookProPenryn */ | 71 | /* MacbookProPenryn */ |
| 71 | ATP_DEVICE(ATP_WELLSPRING2_ANSI), | 72 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), |
| 72 | ATP_DEVICE(ATP_WELLSPRING2_ISO), | 73 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), |
| 73 | ATP_DEVICE(ATP_WELLSPRING2_JIS), | 74 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), |
| 74 | /* Terminating entry */ | 75 | /* Terminating entry */ |
| 75 | {} | 76 | {} |
| 76 | }; | 77 | }; |
| 77 | MODULE_DEVICE_TABLE(usb, atp_table); | 78 | MODULE_DEVICE_TABLE(usb, bcm5974_table); |
| 78 | 79 | ||
| 79 | MODULE_AUTHOR("Henrik Rydberg"); | 80 | MODULE_AUTHOR("Henrik Rydberg"); |
| 80 | MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver"); | 81 | MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver"); |
| @@ -125,7 +126,7 @@ struct tp_data { | |||
| 125 | }; | 126 | }; |
| 126 | 127 | ||
| 127 | /* device-specific parameters */ | 128 | /* device-specific parameters */ |
| 128 | struct atp_params { | 129 | struct bcm5974_param { |
| 129 | int dim; /* logical dimension */ | 130 | int dim; /* logical dimension */ |
| 130 | int fuzz; /* logical noise value */ | 131 | int fuzz; /* logical noise value */ |
| 131 | int devmin; /* device minimum reading */ | 132 | int devmin; /* device minimum reading */ |
| @@ -133,26 +134,27 @@ struct atp_params { | |||
| 133 | }; | 134 | }; |
| 134 | 135 | ||
| 135 | /* device-specific configuration */ | 136 | /* device-specific configuration */ |
| 136 | struct atp_config { | 137 | struct bcm5974_config { |
| 137 | int ansi, iso, jis; /* the product id of this device */ | 138 | int ansi, iso, jis; /* the product id of this device */ |
| 138 | int bt_ep; /* the endpoint of the button interface */ | 139 | int bt_ep; /* the endpoint of the button interface */ |
| 139 | int bt_datalen; /* data length of the button interface */ | 140 | int bt_datalen; /* data length of the button interface */ |
| 140 | int tp_ep; /* the endpoint of the trackpad interface */ | 141 | int tp_ep; /* the endpoint of the trackpad interface */ |
| 141 | int tp_datalen; /* data length of the trackpad interface */ | 142 | int tp_datalen; /* data length of the trackpad interface */ |
| 142 | struct atp_params p; /* finger pressure limits */ | 143 | struct bcm5974_param p; /* finger pressure limits */ |
| 143 | struct atp_params w; /* finger width limits */ | 144 | struct bcm5974_param w; /* finger width limits */ |
| 144 | struct atp_params x; /* horizontal limits */ | 145 | struct bcm5974_param x; /* horizontal limits */ |
| 145 | struct atp_params y; /* vertical limits */ | 146 | struct bcm5974_param y; /* vertical limits */ |
| 146 | }; | 147 | }; |
| 147 | 148 | ||
| 148 | /* logical device structure */ | 149 | /* logical device structure */ |
| 149 | struct atp { | 150 | struct bcm5974 { |
| 150 | char phys[64]; | 151 | char phys[64]; |
| 151 | struct usb_device *udev; /* usb device */ | 152 | struct usb_device *udev; /* usb device */ |
| 152 | struct input_dev *input; /* input dev */ | 153 | struct input_dev *input; /* input dev */ |
| 153 | struct atp_config cfg; /* device configuration */ | 154 | struct bcm5974_config cfg; /* device configuration */ |
| 154 | int open; /* >0: open, else closed */ | 155 | struct mutex mutex; /* serialize access to open/suspend */ |
| 155 | int suspended; /* >0: suspended, else open */ | 156 | int opened; /* >0: opened, else closed */ |
| 157 | int manually_suspended; /* >0: manually suspended */ | ||
| 156 | struct urb *bt_urb; /* button usb request block */ | 158 | struct urb *bt_urb; /* button usb request block */ |
| 157 | struct bt_data *bt_data; /* button transferred data */ | 159 | struct bt_data *bt_data; /* button transferred data */ |
| 158 | struct urb *tp_urb; /* trackpad usb request block */ | 160 | struct urb *tp_urb; /* trackpad usb request block */ |
| @@ -171,11 +173,11 @@ struct atp { | |||
| 171 | #define SN_COORD 250 /* coordinate signal-to-noise ratio */ | 173 | #define SN_COORD 250 /* coordinate signal-to-noise ratio */ |
| 172 | 174 | ||
| 173 | /* device constants */ | 175 | /* device constants */ |
| 174 | static const struct atp_config atp_config_table[] = { | 176 | static const struct bcm5974_config bcm5974_config_table[] = { |
| 175 | { | 177 | { |
| 176 | ATP_WELLSPRING_ANSI, | 178 | USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, |
| 177 | ATP_WELLSPRING_ISO, | 179 | USB_DEVICE_ID_APPLE_WELLSPRING_ISO, |
| 178 | ATP_WELLSPRING_JIS, | 180 | USB_DEVICE_ID_APPLE_WELLSPRING_JIS, |
| 179 | 0x84, sizeof(struct bt_data), | 181 | 0x84, sizeof(struct bt_data), |
| 180 | 0x81, sizeof(struct tp_data), | 182 | 0x81, sizeof(struct tp_data), |
| 181 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, | 183 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, |
| @@ -184,9 +186,9 @@ static const struct atp_config atp_config_table[] = { | |||
| 184 | { DIM_Y, DIM_Y / SN_COORD, -172, 5820 } | 186 | { DIM_Y, DIM_Y / SN_COORD, -172, 5820 } |
| 185 | }, | 187 | }, |
| 186 | { | 188 | { |
| 187 | ATP_WELLSPRING2_ANSI, | 189 | USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, |
| 188 | ATP_WELLSPRING2_ISO, | 190 | USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, |
| 189 | ATP_WELLSPRING2_JIS, | 191 | USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, |
| 190 | 0x84, sizeof(struct bt_data), | 192 | 0x84, sizeof(struct bt_data), |
| 191 | 0x81, sizeof(struct tp_data), | 193 | 0x81, sizeof(struct tp_data), |
| 192 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, | 194 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, |
| @@ -198,15 +200,14 @@ static const struct atp_config atp_config_table[] = { | |||
| 198 | }; | 200 | }; |
| 199 | 201 | ||
| 200 | /* return the device-specific configuration by device */ | 202 | /* return the device-specific configuration by device */ |
| 201 | static const struct atp_config *atp_product_config(struct usb_device *udev) | 203 | static const struct bcm5974_config *bcm5974_get_config(struct usb_device *udev) |
| 202 | { | 204 | { |
| 203 | u16 id = le16_to_cpu(udev->descriptor.idProduct); | 205 | u16 id = le16_to_cpu(udev->descriptor.idProduct); |
| 204 | const struct atp_config *config; | 206 | const struct bcm5974_config *cfg; |
| 205 | for (config = atp_config_table; config->ansi; ++config) | 207 | for (cfg = bcm5974_config_table; cfg->ansi; ++cfg) |
| 206 | if (config->ansi == id || config->iso == id || | 208 | if (cfg->ansi == id || cfg->iso == id || cfg->jis == id) |
| 207 | config->jis == id) | 209 | return cfg; |
| 208 | return config; | 210 | return bcm5974_config_table; |
| 209 | return atp_config_table; | ||
| 210 | } | 211 | } |
| 211 | 212 | ||
| 212 | /* convert 16-bit little endian to signed integer */ | 213 | /* convert 16-bit little endian to signed integer */ |
| @@ -216,33 +217,55 @@ static inline int raw2int(__le16 x) | |||
| 216 | } | 217 | } |
| 217 | 218 | ||
| 218 | /* scale device data to logical dimensions (asserts devmin < devmax) */ | 219 | /* scale device data to logical dimensions (asserts devmin < devmax) */ |
| 219 | static inline int int2scale(const struct atp_params *p, int x) | 220 | static inline int int2scale(const struct bcm5974_param *p, int x) |
| 220 | { | 221 | { |
| 221 | return x * p->dim / (p->devmax - p->devmin); | 222 | return x * p->dim / (p->devmax - p->devmin); |
| 222 | } | 223 | } |
| 223 | 224 | ||
| 224 | /* all logical value ranges are [0,dim). */ | 225 | /* all logical value ranges are [0,dim). */ |
| 225 | static inline int int2bound(const struct atp_params *p, int x) | 226 | static inline int int2bound(const struct bcm5974_param *p, int x) |
| 226 | { | 227 | { |
| 227 | int s = int2scale(p, x); | 228 | int s = int2scale(p, x); |
| 228 | return s < 0 ? 0 : s >= p->dim ? p->dim - 1 : s; | 229 | return s < 0 ? 0 : s >= p->dim ? p->dim - 1 : s; |
| 229 | } | 230 | } |
| 230 | 231 | ||
| 232 | /* setup which logical events to report */ | ||
| 233 | static void setup_events_to_report(struct input_dev *input_dev, | ||
| 234 | const struct bcm5974_config *cfg) | ||
| 235 | { | ||
| 236 | set_bit(EV_ABS, input_dev->evbit); | ||
| 237 | input_set_abs_params(input_dev, ABS_PRESSURE, | ||
| 238 | 0, cfg->p.dim, cfg->p.fuzz, 0); | ||
| 239 | input_set_abs_params(input_dev, ABS_TOOL_WIDTH, | ||
| 240 | 0, cfg->w.dim, cfg->w.fuzz, 0); | ||
| 241 | input_set_abs_params(input_dev, ABS_X, | ||
| 242 | 0, cfg->x.dim, cfg->x.fuzz, 0); | ||
| 243 | input_set_abs_params(input_dev, ABS_Y, | ||
| 244 | 0, cfg->y.dim, cfg->y.fuzz, 0); | ||
| 245 | |||
| 246 | set_bit(EV_KEY, input_dev->evbit); | ||
| 247 | set_bit(BTN_TOOL_FINGER, input_dev->keybit); | ||
| 248 | set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | ||
| 249 | set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | ||
| 250 | set_bit(BTN_LEFT, input_dev->keybit); | ||
| 251 | } | ||
| 252 | |||
| 231 | /* report button data as logical button state */ | 253 | /* report button data as logical button state */ |
| 232 | static int report_bt_state(struct atp *dev, int size) | 254 | static int report_bt_state(struct bcm5974 *dev, int size) |
| 233 | { | 255 | { |
| 234 | if (size != sizeof(struct bt_data)) | 256 | if (size != sizeof(struct bt_data)) |
| 235 | return -EIO; | 257 | return -EIO; |
| 236 | 258 | ||
| 237 | input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); | 259 | input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); |
| 260 | input_sync(dev->input); | ||
| 238 | 261 | ||
| 239 | return 0; | 262 | return 0; |
| 240 | } | 263 | } |
| 241 | 264 | ||
| 242 | /* report trackpad data as logical trackpad state */ | 265 | /* report trackpad data as logical trackpad state */ |
| 243 | static int report_tp_state(struct atp *dev, int size) | 266 | static int report_tp_state(struct bcm5974 *dev, int size) |
| 244 | { | 267 | { |
| 245 | const struct atp_config *c = &dev->cfg; | 268 | const struct bcm5974_config *c = &dev->cfg; |
| 246 | const struct tp_finger *f = dev->tp_data->finger; | 269 | const struct tp_finger *f = dev->tp_data->finger; |
| 247 | const int fingers = (size - 26) / 28; | 270 | const int fingers = (size - 26) / 28; |
| 248 | int p, w, x, y, n; | 271 | int p, w, x, y, n; |
| @@ -255,6 +278,7 @@ static int report_tp_state(struct atp *dev, int size) | |||
| 255 | input_report_key(dev->input, BTN_TOOL_FINGER, false); | 278 | input_report_key(dev->input, BTN_TOOL_FINGER, false); |
| 256 | input_report_key(dev->input, BTN_TOOL_DOUBLETAP, false); | 279 | input_report_key(dev->input, BTN_TOOL_DOUBLETAP, false); |
| 257 | input_report_key(dev->input, BTN_TOOL_TRIPLETAP, false); | 280 | input_report_key(dev->input, BTN_TOOL_TRIPLETAP, false); |
| 281 | input_sync(dev->input); | ||
| 258 | return 0; | 282 | return 0; |
| 259 | } | 283 | } |
| 260 | 284 | ||
| @@ -274,17 +298,18 @@ static int report_tp_state(struct atp *dev, int size) | |||
| 274 | input_report_key(dev->input, BTN_TOOL_FINGER, n == 1); | 298 | input_report_key(dev->input, BTN_TOOL_FINGER, n == 1); |
| 275 | input_report_key(dev->input, BTN_TOOL_DOUBLETAP, n == 2); | 299 | input_report_key(dev->input, BTN_TOOL_DOUBLETAP, n == 2); |
| 276 | input_report_key(dev->input, BTN_TOOL_TRIPLETAP, n > 2); | 300 | input_report_key(dev->input, BTN_TOOL_TRIPLETAP, n > 2); |
| 301 | input_sync(dev->input); | ||
| 277 | return 0; | 302 | return 0; |
| 278 | } | 303 | } |
| 279 | 304 | ||
| 280 | /* Wellspring initialization constants */ | 305 | /* Wellspring initialization constants */ |
| 281 | #define ATP_WELLSPRING_MODE_READ_REQUEST_ID 1 | 306 | #define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1 |
| 282 | #define ATP_WELLSPRING_MODE_WRITE_REQUEST_ID 9 | 307 | #define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9 |
| 283 | #define ATP_WELLSPRING_MODE_REQUEST_VALUE 0x300 | 308 | #define BCM5974_WELLSPRING_MODE_REQUEST_VALUE 0x300 |
| 284 | #define ATP_WELLSPRING_MODE_REQUEST_INDEX 0 | 309 | #define BCM5974_WELLSPRING_MODE_REQUEST_INDEX 0 |
| 285 | #define ATP_WELLSPRING_MODE_VENDOR_VALUE 0x01 | 310 | #define BCM5974_WELLSPRING_MODE_VENDOR_VALUE 0x01 |
| 286 | 311 | ||
| 287 | static int atp_wellspring_mode(struct atp *dev) | 312 | static int bcm5974_wellspring_mode(struct bcm5974 *dev) |
| 288 | { | 313 | { |
| 289 | char *data = kmalloc(8, GFP_KERNEL); | 314 | char *data = kmalloc(8, GFP_KERNEL); |
| 290 | int error = 0, size; | 315 | int error = 0, size; |
| @@ -297,10 +322,10 @@ static int atp_wellspring_mode(struct atp *dev) | |||
| 297 | 322 | ||
| 298 | /* read configuration */ | 323 | /* read configuration */ |
| 299 | size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), | 324 | size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), |
| 300 | ATP_WELLSPRING_MODE_READ_REQUEST_ID, | 325 | BCM5974_WELLSPRING_MODE_READ_REQUEST_ID, |
| 301 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 326 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
| 302 | ATP_WELLSPRING_MODE_REQUEST_VALUE, | 327 | BCM5974_WELLSPRING_MODE_REQUEST_VALUE, |
| 303 | ATP_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000); | 328 | BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000); |
| 304 | 329 | ||
| 305 | if (size != 8) { | 330 | if (size != 8) { |
| 306 | err("bcm5974: could not read from device"); | 331 | err("bcm5974: could not read from device"); |
| @@ -309,14 +334,14 @@ static int atp_wellspring_mode(struct atp *dev) | |||
| 309 | } | 334 | } |
| 310 | 335 | ||
| 311 | /* apply the mode switch */ | 336 | /* apply the mode switch */ |
| 312 | data[0] = ATP_WELLSPRING_MODE_VENDOR_VALUE; | 337 | data[0] = BCM5974_WELLSPRING_MODE_VENDOR_VALUE; |
| 313 | 338 | ||
| 314 | /* write configuration */ | 339 | /* write configuration */ |
| 315 | size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), | 340 | size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), |
| 316 | ATP_WELLSPRING_MODE_WRITE_REQUEST_ID, | 341 | BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID, |
| 317 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 342 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
| 318 | ATP_WELLSPRING_MODE_REQUEST_VALUE, | 343 | BCM5974_WELLSPRING_MODE_REQUEST_VALUE, |
| 319 | ATP_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000); | 344 | BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000); |
| 320 | 345 | ||
| 321 | if (size != 8) { | 346 | if (size != 8) { |
| 322 | err("bcm5974: could not write to device"); | 347 | err("bcm5974: could not write to device"); |
| @@ -336,7 +361,7 @@ error: | |||
| 336 | 361 | ||
| 337 | static void irq_button(struct urb *urb) | 362 | static void irq_button(struct urb *urb) |
| 338 | { | 363 | { |
| 339 | struct atp *dev = urb->context; | 364 | struct bcm5974 *dev = urb->context; |
| 340 | int error; | 365 | int error; |
| 341 | 366 | ||
| 342 | switch (urb->status) { | 367 | switch (urb->status) { |
| @@ -353,13 +378,9 @@ static void irq_button(struct urb *urb) | |||
| 353 | goto exit; | 378 | goto exit; |
| 354 | } | 379 | } |
| 355 | 380 | ||
| 356 | if (report_bt_state(dev, dev->bt_urb->actual_length)) { | 381 | if (report_bt_state(dev, dev->bt_urb->actual_length)) |
| 357 | dprintk(1, "bcm5974: bad button package, length: %d\n", | 382 | dprintk(1, "bcm5974: bad button package, length: %d\n", |
| 358 | dev->bt_urb->actual_length); | 383 | dev->bt_urb->actual_length); |
| 359 | goto exit; | ||
| 360 | } | ||
| 361 | |||
| 362 | input_sync(dev->input); | ||
| 363 | 384 | ||
| 364 | exit: | 385 | exit: |
| 365 | error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC); | 386 | error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC); |
| @@ -369,7 +390,7 @@ exit: | |||
| 369 | 390 | ||
| 370 | static void irq_trackpad(struct urb *urb) | 391 | static void irq_trackpad(struct urb *urb) |
| 371 | { | 392 | { |
| 372 | struct atp *dev = urb->context; | 393 | struct bcm5974 *dev = urb->context; |
| 373 | int error; | 394 | int error; |
| 374 | 395 | ||
| 375 | switch (urb->status) { | 396 | switch (urb->status) { |
| @@ -390,13 +411,9 @@ static void irq_trackpad(struct urb *urb) | |||
| 390 | if (dev->tp_urb->actual_length == 2) | 411 | if (dev->tp_urb->actual_length == 2) |
| 391 | goto exit; | 412 | goto exit; |
| 392 | 413 | ||
| 393 | if (report_tp_state(dev, dev->tp_urb->actual_length)) { | 414 | if (report_tp_state(dev, dev->tp_urb->actual_length)) |
| 394 | dprintk(1, "bcm5974: bad trackpad package, length: %d\n", | 415 | dprintk(1, "bcm5974: bad trackpad package, length: %d\n", |
| 395 | dev->tp_urb->actual_length); | 416 | dev->tp_urb->actual_length); |
| 396 | goto exit; | ||
| 397 | } | ||
| 398 | |||
| 399 | input_sync(dev->input); | ||
| 400 | 417 | ||
| 401 | exit: | 418 | exit: |
| 402 | error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC); | 419 | error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC); |
| @@ -417,99 +434,149 @@ exit: | |||
| 417 | * device, resulting in trackpad malfunction under certain | 434 | * device, resulting in trackpad malfunction under certain |
| 418 | * circumstances. To get around this problem, there is at least one | 435 | * circumstances. To get around this problem, there is at least one |
| 419 | * example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to | 436 | * example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to |
| 420 | * recieve a reset_resume request rather than the normal resume. Since | 437 | * recieve a reset_resume request rather than the normal resume. |
| 421 | * the implementation of reset_resume is equal to mode switch plus | 438 | * Since the implementation of reset_resume is equal to mode switch |
| 422 | * open, it seems easier to always do the switch while opening the | 439 | * plus start_traffic, it seems easier to always do the switch when |
| 423 | * device. | 440 | * starting traffic on the device. |
| 424 | */ | 441 | */ |
| 425 | static int atp_open(struct input_dev *input) | 442 | static int start_traffic(struct bcm5974 *dev) |
| 426 | { | 443 | { |
| 427 | struct atp *dev = input_get_drvdata(input); | 444 | if (bcm5974_wellspring_mode(dev)) { |
| 428 | 445 | dprintk(1, "bcm5974: mode switch failed\n"); | |
| 429 | if (!dev->open) { | 446 | goto error; |
| 430 | if (atp_wellspring_mode(dev)) { | ||
| 431 | dprintk(1, "bcm5974: mode switch failed\n"); | ||
| 432 | goto error; | ||
| 433 | } | ||
| 434 | if (usb_submit_urb(dev->bt_urb, GFP_KERNEL)) | ||
| 435 | goto error; | ||
| 436 | if (usb_submit_urb(dev->tp_urb, GFP_KERNEL)) | ||
| 437 | goto err_kill_bt; | ||
| 438 | } | 447 | } |
| 448 | if (usb_submit_urb(dev->bt_urb, GFP_KERNEL)) | ||
| 449 | goto error; | ||
| 450 | if (usb_submit_urb(dev->tp_urb, GFP_KERNEL)) | ||
| 451 | goto err_kill_bt; | ||
| 439 | 452 | ||
| 440 | dev->open = 1; | ||
| 441 | dev->suspended = 0; | ||
| 442 | return 0; | 453 | return 0; |
| 443 | |||
| 444 | err_kill_bt: | 454 | err_kill_bt: |
| 445 | usb_kill_urb(dev->bt_urb); | 455 | usb_kill_urb(dev->bt_urb); |
| 446 | error: | 456 | error: |
| 447 | return -EIO; | 457 | return -EIO; |
| 448 | } | 458 | } |
| 449 | 459 | ||
| 450 | static void atp_close(struct input_dev *input) | 460 | static void pause_traffic(struct bcm5974 *dev) |
| 451 | { | 461 | { |
| 452 | struct atp *dev = input_get_drvdata(input); | ||
| 453 | |||
| 454 | usb_kill_urb(dev->tp_urb); | 462 | usb_kill_urb(dev->tp_urb); |
| 455 | usb_kill_urb(dev->bt_urb); | 463 | usb_kill_urb(dev->bt_urb); |
| 464 | } | ||
| 456 | 465 | ||
| 457 | dev->open = 0; | 466 | /* |
| 458 | dev->suspended = 0; | 467 | * The code below implements open/close and manual suspend/resume. |
| 468 | * All functions may be called in random order. | ||
| 469 | * | ||
| 470 | * Opening a suspended device fails with EACCES - permission denied. | ||
| 471 | * | ||
| 472 | * Failing a resume leaves the device resumed but closed. | ||
| 473 | */ | ||
| 474 | static int bcm5974_open(struct input_dev *input) | ||
| 475 | { | ||
| 476 | struct bcm5974 *dev = input_get_drvdata(input); | ||
| 477 | int error = 0; | ||
| 478 | |||
| 479 | mutex_lock(&dev->mutex); | ||
| 480 | if (dev->manually_suspended) | ||
| 481 | error = -EACCES; | ||
| 482 | else if (!dev->opened) | ||
| 483 | error = start_traffic(dev); | ||
| 484 | dev->opened = !error; | ||
| 485 | mutex_unlock(&dev->mutex); | ||
| 486 | |||
| 487 | return error; | ||
| 459 | } | 488 | } |
| 460 | 489 | ||
| 461 | static int atp_probe(struct usb_interface *iface, | 490 | static void bcm5974_close(struct input_dev *input) |
| 491 | { | ||
| 492 | struct bcm5974 *dev = input_get_drvdata(input); | ||
| 493 | |||
| 494 | mutex_lock(&dev->mutex); | ||
| 495 | if (!dev->manually_suspended) | ||
| 496 | pause_traffic(dev); | ||
| 497 | dev->opened = 0; | ||
| 498 | mutex_unlock(&dev->mutex); | ||
| 499 | } | ||
| 500 | |||
| 501 | static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message) | ||
| 502 | { | ||
| 503 | struct bcm5974 *dev = usb_get_intfdata(iface); | ||
| 504 | |||
| 505 | if (dev) { | ||
| 506 | mutex_lock(&dev->mutex); | ||
| 507 | if (dev->opened && !dev->manually_suspended) | ||
| 508 | pause_traffic(dev); | ||
| 509 | dev->manually_suspended++; | ||
| 510 | mutex_unlock(&dev->mutex); | ||
| 511 | } | ||
| 512 | |||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | |||
| 516 | static int bcm5974_resume(struct usb_interface *iface) | ||
| 517 | { | ||
| 518 | struct bcm5974 *dev = usb_get_intfdata(iface); | ||
| 519 | int error = 0; | ||
| 520 | |||
| 521 | if (dev) { | ||
| 522 | mutex_lock(&dev->mutex); | ||
| 523 | if (dev->manually_suspended) | ||
| 524 | dev->manually_suspended--; | ||
| 525 | if (dev->opened && !dev->manually_suspended) | ||
| 526 | error = start_traffic(dev); | ||
| 527 | if (error) | ||
| 528 | dev->opened = 0; | ||
| 529 | mutex_unlock(&dev->mutex); | ||
| 530 | } | ||
| 531 | |||
| 532 | return error; | ||
| 533 | } | ||
| 534 | |||
| 535 | static int bcm5974_probe(struct usb_interface *iface, | ||
| 462 | const struct usb_device_id *id) | 536 | const struct usb_device_id *id) |
| 463 | { | 537 | { |
| 464 | struct usb_device *udev = interface_to_usbdev(iface); | 538 | struct usb_device *udev = interface_to_usbdev(iface); |
| 465 | const struct atp_config *cfg; | 539 | const struct bcm5974_config *cfg; |
| 466 | struct atp *dev; | 540 | struct bcm5974 *dev; |
| 467 | struct input_dev *input_dev; | 541 | struct input_dev *input_dev; |
| 468 | int error = 0; | 542 | int error = -ENOMEM; |
| 469 | 543 | ||
| 470 | /* find the product index */ | 544 | /* find the product index */ |
| 471 | cfg = atp_product_config(udev); | 545 | cfg = bcm5974_get_config(udev); |
| 472 | 546 | ||
| 473 | /* allocate memory for our device state and initialize it */ | 547 | /* allocate memory for our device state and initialize it */ |
| 474 | dev = kzalloc(sizeof(struct atp), GFP_KERNEL); | 548 | dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL); |
| 475 | input_dev = input_allocate_device(); | 549 | input_dev = input_allocate_device(); |
| 476 | if (!dev || !input_dev) { | 550 | if (!dev || !input_dev) { |
| 477 | err("bcm5974: out of memory"); | 551 | err("bcm5974: out of memory"); |
| 478 | error = -ENOMEM; | ||
| 479 | goto err_free_devs; | 552 | goto err_free_devs; |
| 480 | } | 553 | } |
| 481 | 554 | ||
| 482 | dev->udev = udev; | 555 | dev->udev = udev; |
| 483 | dev->input = input_dev; | 556 | dev->input = input_dev; |
| 484 | dev->cfg = *cfg; | 557 | dev->cfg = *cfg; |
| 558 | mutex_init(&dev->mutex); | ||
| 485 | 559 | ||
| 560 | /* setup urbs */ | ||
| 486 | dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL); | 561 | dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL); |
| 487 | if (!dev->bt_urb) { | 562 | if (!dev->bt_urb) |
| 488 | error = -ENOMEM; | ||
| 489 | goto err_free_devs; | 563 | goto err_free_devs; |
| 490 | } | ||
| 491 | 564 | ||
| 492 | dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL); | 565 | dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL); |
| 493 | if (!dev->tp_urb) { | 566 | if (!dev->tp_urb) |
| 494 | error = -ENOMEM; | ||
| 495 | goto err_free_bt_urb; | 567 | goto err_free_bt_urb; |
| 496 | } | ||
| 497 | 568 | ||
| 498 | dev->bt_data = usb_buffer_alloc(dev->udev, | 569 | dev->bt_data = usb_buffer_alloc(dev->udev, |
| 499 | dev->cfg.bt_datalen, GFP_KERNEL, | 570 | dev->cfg.bt_datalen, GFP_KERNEL, |
| 500 | &dev->bt_urb->transfer_dma); | 571 | &dev->bt_urb->transfer_dma); |
| 501 | if (!dev->bt_data) { | 572 | if (!dev->bt_data) |
| 502 | error = -ENOMEM; | ||
| 503 | goto err_free_urb; | 573 | goto err_free_urb; |
| 504 | } | ||
| 505 | 574 | ||
| 506 | dev->tp_data = usb_buffer_alloc(dev->udev, | 575 | dev->tp_data = usb_buffer_alloc(dev->udev, |
| 507 | dev->cfg.tp_datalen, GFP_KERNEL, | 576 | dev->cfg.tp_datalen, GFP_KERNEL, |
| 508 | &dev->tp_urb->transfer_dma); | 577 | &dev->tp_urb->transfer_dma); |
| 509 | if (!dev->tp_data) { | 578 | if (!dev->tp_data) |
| 510 | error = -ENOMEM; | ||
| 511 | goto err_free_bt_buffer; | 579 | goto err_free_bt_buffer; |
| 512 | } | ||
| 513 | 580 | ||
| 514 | usb_fill_int_urb(dev->bt_urb, udev, | 581 | usb_fill_int_urb(dev->bt_urb, udev, |
| 515 | usb_rcvintpipe(udev, cfg->bt_ep), | 582 | usb_rcvintpipe(udev, cfg->bt_ep), |
| @@ -521,6 +588,7 @@ static int atp_probe(struct usb_interface *iface, | |||
| 521 | dev->tp_data, dev->cfg.tp_datalen, | 588 | dev->tp_data, dev->cfg.tp_datalen, |
| 522 | irq_trackpad, dev, 1); | 589 | irq_trackpad, dev, 1); |
| 523 | 590 | ||
| 591 | /* create bcm5974 device */ | ||
| 524 | usb_make_path(udev, dev->phys, sizeof(dev->phys)); | 592 | usb_make_path(udev, dev->phys, sizeof(dev->phys)); |
| 525 | strlcat(dev->phys, "/input0", sizeof(dev->phys)); | 593 | strlcat(dev->phys, "/input0", sizeof(dev->phys)); |
| 526 | 594 | ||
| @@ -531,24 +599,10 @@ static int atp_probe(struct usb_interface *iface, | |||
| 531 | 599 | ||
| 532 | input_set_drvdata(input_dev, dev); | 600 | input_set_drvdata(input_dev, dev); |
| 533 | 601 | ||
| 534 | input_dev->open = atp_open; | 602 | input_dev->open = bcm5974_open; |
| 535 | input_dev->close = atp_close; | 603 | input_dev->close = bcm5974_close; |
| 536 | 604 | ||
| 537 | set_bit(EV_ABS, input_dev->evbit); | 605 | setup_events_to_report(input_dev, cfg); |
| 538 | input_set_abs_params(input_dev, ABS_PRESSURE, | ||
| 539 | 0, cfg->p.dim, cfg->p.fuzz, 0); | ||
| 540 | input_set_abs_params(input_dev, ABS_TOOL_WIDTH, | ||
| 541 | 0, cfg->w.dim, cfg->w.fuzz, 0); | ||
| 542 | input_set_abs_params(input_dev, ABS_X, | ||
| 543 | 0, cfg->x.dim, cfg->x.fuzz, 0); | ||
| 544 | input_set_abs_params(input_dev, ABS_Y, | ||
| 545 | 0, cfg->y.dim, cfg->y.fuzz, 0); | ||
| 546 | |||
| 547 | set_bit(EV_KEY, input_dev->evbit); | ||
| 548 | set_bit(BTN_TOOL_FINGER, input_dev->keybit); | ||
| 549 | set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | ||
| 550 | set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | ||
| 551 | set_bit(BTN_LEFT, input_dev->keybit); | ||
| 552 | 606 | ||
| 553 | error = input_register_device(dev->input); | 607 | error = input_register_device(dev->input); |
| 554 | if (error) | 608 | if (error) |
| @@ -571,77 +625,49 @@ err_free_bt_urb: | |||
| 571 | usb_free_urb(dev->bt_urb); | 625 | usb_free_urb(dev->bt_urb); |
| 572 | err_free_devs: | 626 | err_free_devs: |
| 573 | usb_set_intfdata(iface, NULL); | 627 | usb_set_intfdata(iface, NULL); |
| 574 | kfree(dev); | ||
| 575 | input_free_device(input_dev); | 628 | input_free_device(input_dev); |
| 629 | kfree(dev); | ||
| 576 | return error; | 630 | return error; |
| 577 | } | 631 | } |
| 578 | 632 | ||
| 579 | static void atp_disconnect(struct usb_interface *iface) | 633 | static void bcm5974_disconnect(struct usb_interface *iface) |
| 580 | { | 634 | { |
| 581 | struct atp *dev = usb_get_intfdata(iface); | 635 | struct bcm5974 *dev = usb_get_intfdata(iface); |
| 582 | 636 | ||
| 583 | usb_set_intfdata(iface, NULL); | 637 | usb_set_intfdata(iface, NULL); |
| 584 | 638 | ||
| 585 | if (dev) { | 639 | input_unregister_device(dev->input); |
| 586 | input_unregister_device(dev->input); | 640 | usb_buffer_free(dev->udev, dev->cfg.tp_datalen, |
| 587 | usb_buffer_free(dev->udev, dev->cfg.tp_datalen, | 641 | dev->tp_data, dev->tp_urb->transfer_dma); |
| 588 | dev->tp_data, dev->tp_urb->transfer_dma); | 642 | usb_buffer_free(dev->udev, dev->cfg.bt_datalen, |
| 589 | usb_buffer_free(dev->udev, dev->cfg.bt_datalen, | 643 | dev->bt_data, dev->bt_urb->transfer_dma); |
| 590 | dev->bt_data, dev->bt_urb->transfer_dma); | 644 | usb_free_urb(dev->tp_urb); |
| 591 | usb_free_urb(dev->tp_urb); | 645 | usb_free_urb(dev->bt_urb); |
| 592 | usb_free_urb(dev->bt_urb); | 646 | kfree(dev); |
| 593 | kfree(dev); | ||
| 594 | } | ||
| 595 | 647 | ||
| 596 | printk(KERN_INFO "bcm5974: disconnected\n"); | 648 | printk(KERN_INFO "bcm5974: disconnected\n"); |
| 597 | } | 649 | } |
| 598 | 650 | ||
| 599 | static int atp_suspend(struct usb_interface *iface, pm_message_t message) | 651 | static struct usb_driver bcm5974_driver = { |
| 600 | { | ||
| 601 | struct atp *dev = usb_get_intfdata(iface); | ||
| 602 | |||
| 603 | if (dev) { | ||
| 604 | if (!dev->suspended) | ||
| 605 | atp_close(dev->input); | ||
| 606 | dev->suspended++; | ||
| 607 | } | ||
| 608 | |||
| 609 | return 0; | ||
| 610 | } | ||
| 611 | |||
| 612 | static int atp_resume(struct usb_interface *iface) | ||
| 613 | { | ||
| 614 | struct atp *dev = usb_get_intfdata(iface); | ||
| 615 | int error = 0; | ||
| 616 | |||
| 617 | if (dev && dev->suspended) { | ||
| 618 | if (!--dev->suspended) | ||
| 619 | error = atp_open(dev->input); | ||
| 620 | } | ||
| 621 | |||
| 622 | return error; | ||
| 623 | } | ||
| 624 | |||
| 625 | static struct usb_driver atp_driver = { | ||
| 626 | .name = "bcm5974", | 652 | .name = "bcm5974", |
| 627 | .probe = atp_probe, | 653 | .probe = bcm5974_probe, |
| 628 | .disconnect = atp_disconnect, | 654 | .disconnect = bcm5974_disconnect, |
| 629 | .suspend = atp_suspend, | 655 | .suspend = bcm5974_suspend, |
| 630 | .resume = atp_resume, | 656 | .resume = bcm5974_resume, |
| 631 | .reset_resume = atp_resume, | 657 | .reset_resume = bcm5974_resume, |
| 632 | .id_table = atp_table, | 658 | .id_table = bcm5974_table, |
| 633 | }; | 659 | }; |
| 634 | 660 | ||
| 635 | static int __init atp_init(void) | 661 | static int __init bcm5974_init(void) |
| 636 | { | 662 | { |
| 637 | return usb_register(&atp_driver); | 663 | return usb_register(&bcm5974_driver); |
| 638 | } | 664 | } |
| 639 | 665 | ||
| 640 | static void __exit atp_exit(void) | 666 | static void __exit bcm5974_exit(void) |
| 641 | { | 667 | { |
| 642 | usb_deregister(&atp_driver); | 668 | usb_deregister(&bcm5974_driver); |
| 643 | } | 669 | } |
| 644 | 670 | ||
| 645 | module_init(atp_init); | 671 | module_init(bcm5974_init); |
| 646 | module_exit(atp_exit); | 672 | module_exit(bcm5974_exit); |
| 647 | 673 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | PACKAGE_NAME="bcm5974" | 1 | PACKAGE_NAME="bcm5974" |
| 2 | PACKAGE_VERSION="0.57" | 2 | PACKAGE_VERSION="0.58" |
| 3 | MAKE[0]="make -C ${kernel_source_dir} | 3 | MAKE[0]="make -C ${kernel_source_dir} |
| 4 | SUBDIRS=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build modules" | 4 | SUBDIRS=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build modules" |
| 5 | BUILT_MODULE_NAME[0]="bcm5974" | 5 | BUILT_MODULE_NAME[0]="bcm5974" |
