@@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
8484 0xC0 /* End Collection */
8585};
8686
87+ /* Parameter indices */
88+ enum huion_prm {
89+ HUION_PRM_X_LM = 1 ,
90+ HUION_PRM_Y_LM = 2 ,
91+ HUION_PRM_PRESSURE_LM = 4 ,
92+ HUION_PRM_RESOLUTION = 5 ,
93+ HUION_PRM_NUM
94+ };
95+
8796/* Driver data */
8897struct huion_drvdata {
8998 __u8 * rdesc ;
@@ -115,73 +124,92 @@ static int huion_tablet_enable(struct hid_device *hdev)
115124 int rc ;
116125 struct usb_device * usb_dev = hid_to_usb_dev (hdev );
117126 struct huion_drvdata * drvdata = hid_get_drvdata (hdev );
118- __le16 buf [6 ];
127+ __le16 * buf = NULL ;
128+ size_t len ;
129+ s32 params [HUION_PH_ID_NUM ];
130+ s32 resolution ;
131+ __u8 * p ;
132+ s32 v ;
119133
120134 /*
121135 * Read string descriptor containing tablet parameters. The specific
122136 * string descriptor and data were discovered by sniffing the Windows
123137 * driver traffic.
124138 * NOTE: This enables fully-functional tablet mode.
125139 */
140+ len = HUION_PRM_NUM * sizeof (* buf );
141+ buf = kmalloc (len , GFP_KERNEL );
142+ if (buf == NULL ) {
143+ hid_err (hdev , "failed to allocate parameter buffer\n" );
144+ rc = - ENOMEM ;
145+ goto cleanup ;
146+ }
126147 rc = usb_control_msg (usb_dev , usb_rcvctrlpipe (usb_dev , 0 ),
127148 USB_REQ_GET_DESCRIPTOR , USB_DIR_IN ,
128149 (USB_DT_STRING << 8 ) + 0x64 ,
129- 0x0409 , buf , sizeof ( buf ) ,
150+ 0x0409 , buf , len ,
130151 USB_CTRL_GET_TIMEOUT );
131- if (rc == - EPIPE )
132- hid_warn (hdev , "device parameters not found\n" );
133- else if (rc < 0 )
134- hid_warn (hdev , "failed to get device parameters: %d\n" , rc );
135- else if (rc != sizeof (buf ))
136- hid_warn (hdev , "invalid device parameters\n" );
137- else {
138- s32 params [HUION_PH_ID_NUM ];
139- s32 resolution ;
140- __u8 * p ;
141- s32 v ;
152+ if (rc == - EPIPE ) {
153+ hid_err (hdev , "device parameters not found\n" );
154+ rc = - ENODEV ;
155+ goto cleanup ;
156+ } else if (rc < 0 ) {
157+ hid_err (hdev , "failed to get device parameters: %d\n" , rc );
158+ rc = - ENODEV ;
159+ goto cleanup ;
160+ } else if (rc != len ) {
161+ hid_err (hdev , "invalid device parameters\n" );
162+ rc = - ENODEV ;
163+ goto cleanup ;
164+ }
142165
143- /* Extract device parameters */
144- params [HUION_PH_ID_X_LM ] = le16_to_cpu (buf [1 ]);
145- params [HUION_PH_ID_Y_LM ] = le16_to_cpu (buf [2 ]);
146- params [HUION_PH_ID_PRESSURE_LM ] = le16_to_cpu (buf [4 ]);
147- resolution = le16_to_cpu (buf [5 ]);
148- if (resolution == 0 ) {
149- params [HUION_PH_ID_X_PM ] = 0 ;
150- params [HUION_PH_ID_Y_PM ] = 0 ;
151- } else {
152- params [HUION_PH_ID_X_PM ] = params [HUION_PH_ID_X_LM ] *
153- 1000 / resolution ;
154- params [HUION_PH_ID_Y_PM ] = params [HUION_PH_ID_Y_LM ] *
155- 1000 / resolution ;
156- }
166+ /* Extract device parameters */
167+ params [HUION_PH_ID_X_LM ] = le16_to_cpu (buf [HUION_PRM_X_LM ]);
168+ params [HUION_PH_ID_Y_LM ] = le16_to_cpu (buf [HUION_PRM_Y_LM ]);
169+ params [HUION_PH_ID_PRESSURE_LM ] =
170+ le16_to_cpu (buf [HUION_PRM_PRESSURE_LM ]);
171+ resolution = le16_to_cpu (buf [HUION_PRM_RESOLUTION ]);
172+ if (resolution == 0 ) {
173+ params [HUION_PH_ID_X_PM ] = 0 ;
174+ params [HUION_PH_ID_Y_PM ] = 0 ;
175+ } else {
176+ params [HUION_PH_ID_X_PM ] = params [HUION_PH_ID_X_LM ] *
177+ 1000 / resolution ;
178+ params [HUION_PH_ID_Y_PM ] = params [HUION_PH_ID_Y_LM ] *
179+ 1000 / resolution ;
180+ }
157181
158- /* Allocate fixed report descriptor */
159- drvdata -> rdesc = devm_kmalloc (& hdev -> dev ,
160- sizeof (huion_tablet_rdesc_template ),
161- GFP_KERNEL );
162- if (drvdata -> rdesc == NULL ) {
163- hid_err (hdev , "failed to allocate fixed rdesc\n" );
164- return - ENOMEM ;
165- }
166- drvdata -> rsize = sizeof (huion_tablet_rdesc_template );
182+ /* Allocate fixed report descriptor */
183+ drvdata -> rdesc = devm_kmalloc (& hdev -> dev ,
184+ sizeof (huion_tablet_rdesc_template ),
185+ GFP_KERNEL );
186+ if (drvdata -> rdesc == NULL ) {
187+ hid_err (hdev , "failed to allocate fixed rdesc\n" );
188+ rc = - ENOMEM ;
189+ goto cleanup ;
190+ }
191+ drvdata -> rsize = sizeof (huion_tablet_rdesc_template );
167192
168- /* Format fixed report descriptor */
169- memcpy (drvdata -> rdesc , huion_tablet_rdesc_template ,
170- drvdata -> rsize );
171- for (p = drvdata -> rdesc ;
172- p <= drvdata -> rdesc + drvdata -> rsize - 4 ;) {
173- if (p [0 ] == 0xFE && p [1 ] == 0xED && p [2 ] == 0x1D &&
174- p [3 ] < sizeof (params )) {
175- v = params [p [3 ]];
176- put_unaligned (cpu_to_le32 (v ), (s32 * )p );
177- p += 4 ;
178- } else {
179- p ++ ;
180- }
193+ /* Format fixed report descriptor */
194+ memcpy (drvdata -> rdesc , huion_tablet_rdesc_template ,
195+ drvdata -> rsize );
196+ for (p = drvdata -> rdesc ;
197+ p <= drvdata -> rdesc + drvdata -> rsize - 4 ;) {
198+ if (p [0 ] == 0xFE && p [1 ] == 0xED && p [2 ] == 0x1D &&
199+ p [3 ] < sizeof (params )) {
200+ v = params [p [3 ]];
201+ put_unaligned (cpu_to_le32 (v ), (s32 * )p );
202+ p += 4 ;
203+ } else {
204+ p ++ ;
181205 }
182206 }
183207
184- return 0 ;
208+ rc = 0 ;
209+
210+ cleanup :
211+ kfree (buf );
212+ return rc ;
185213}
186214
187215static int huion_probe (struct hid_device * hdev , const struct hid_device_id * id )
0 commit comments