GNU Linux-libre 4.19.207-gnu1
[releases.git] / drivers / hid / intel-ish-hid / ishtp-hid-client.c
1 /*
2  * ISHTP client driver for HID (ISH)
3  *
4  * Copyright (c) 2014-2016, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  */
15
16 #include <linux/module.h>
17 #include <linux/hid.h>
18 #include <linux/sched.h>
19 #include "ishtp/ishtp-dev.h"
20 #include "ishtp/client.h"
21 #include "ishtp-hid.h"
22
23 /* Rx ring buffer pool size */
24 #define HID_CL_RX_RING_SIZE     32
25 #define HID_CL_TX_RING_SIZE     16
26
27 /**
28  * report_bad_packets() - Report bad packets
29  * @hid_ishtp_cl:       Client instance to get stats
30  * @recv_buf:           Raw received host interface message
31  * @cur_pos:            Current position index in payload
32  * @payload_len:        Length of payload expected
33  *
34  * Dumps error in case bad packet is received
35  */
36 static void report_bad_packet(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
37                               size_t cur_pos,  size_t payload_len)
38 {
39         struct hostif_msg *recv_msg = recv_buf;
40         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
41
42         dev_err(&client_data->cl_device->dev, "[hid-ish]: BAD packet %02X\n"
43                 "total_bad=%u cur_pos=%u\n"
44                 "[%02X %02X %02X %02X]\n"
45                 "payload_len=%u\n"
46                 "multi_packet_cnt=%u\n"
47                 "is_response=%02X\n",
48                 recv_msg->hdr.command, client_data->bad_recv_cnt,
49                 (unsigned int)cur_pos,
50                 ((unsigned char *)recv_msg)[0], ((unsigned char *)recv_msg)[1],
51                 ((unsigned char *)recv_msg)[2], ((unsigned char *)recv_msg)[3],
52                 (unsigned int)payload_len, client_data->multi_packet_cnt,
53                 recv_msg->hdr.command & ~CMD_MASK);
54 }
55
56 /**
57  * process_recv() - Received and parse incoming packet
58  * @hid_ishtp_cl:       Client instance to get stats
59  * @recv_buf:           Raw received host interface message
60  * @data_len:           length of the message
61  *
62  * Parse the incoming packet. If it is a response packet then it will update
63  * per instance flags and wake up the caller waiting to for the response.
64  */
65 static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
66                          size_t data_len)
67 {
68         struct hostif_msg *recv_msg;
69         unsigned char *payload;
70         struct device_info *dev_info;
71         int i, j;
72         size_t  payload_len, total_len, cur_pos;
73         int report_type;
74         struct report_list *reports_list;
75         char *reports;
76         size_t report_len;
77         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
78         int curr_hid_dev = client_data->cur_hid_dev;
79
80         payload = recv_buf + sizeof(struct hostif_msg_hdr);
81         total_len = data_len;
82         cur_pos = 0;
83
84         do {
85                 if (cur_pos + sizeof(struct hostif_msg) > total_len) {
86                         dev_err(&client_data->cl_device->dev,
87                                 "[hid-ish]: error, received %u which is less than data header %u\n",
88                                 (unsigned int)data_len,
89                                 (unsigned int)sizeof(struct hostif_msg_hdr));
90                         ++client_data->bad_recv_cnt;
91                         ish_hw_reset(hid_ishtp_cl->dev);
92                         break;
93                 }
94
95                 recv_msg = (struct hostif_msg *)(recv_buf + cur_pos);
96                 payload_len = recv_msg->hdr.size;
97
98                 /* Sanity checks */
99                 if (cur_pos + payload_len + sizeof(struct hostif_msg) >
100                                 total_len) {
101                         ++client_data->bad_recv_cnt;
102                         report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
103                                           payload_len);
104                         ish_hw_reset(hid_ishtp_cl->dev);
105                         break;
106                 }
107
108                 hid_ishtp_trace(client_data,  "%s %d\n",
109                                 __func__, recv_msg->hdr.command & CMD_MASK);
110
111                 switch (recv_msg->hdr.command & CMD_MASK) {
112                 case HOSTIF_DM_ENUM_DEVICES:
113                         if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
114                                         client_data->init_done)) {
115                                 ++client_data->bad_recv_cnt;
116                                 report_bad_packet(hid_ishtp_cl, recv_msg,
117                                                   cur_pos,
118                                                   payload_len);
119                                 ish_hw_reset(hid_ishtp_cl->dev);
120                                 break;
121                         }
122                         client_data->hid_dev_count = (unsigned int)*payload;
123                         if (!client_data->hid_devices)
124                                 client_data->hid_devices = devm_kcalloc(
125                                                 &client_data->cl_device->dev,
126                                                 client_data->hid_dev_count,
127                                                 sizeof(struct device_info),
128                                                 GFP_KERNEL);
129                         if (!client_data->hid_devices) {
130                                 dev_err(&client_data->cl_device->dev,
131                                 "Mem alloc failed for hid device info\n");
132                                 wake_up_interruptible(&client_data->init_wait);
133                                 break;
134                         }
135                         for (i = 0; i < client_data->hid_dev_count; ++i) {
136                                 if (1 + sizeof(struct device_info) * i >=
137                                                 payload_len) {
138                                         dev_err(&client_data->cl_device->dev,
139                                                 "[hid-ish]: [ENUM_DEVICES]: content size %zu is bigger than payload_len %zu\n",
140                                                 1 + sizeof(struct device_info)
141                                                 * i, payload_len);
142                                 }
143
144                                 if (1 + sizeof(struct device_info) * i >=
145                                                 data_len)
146                                         break;
147
148                                 dev_info = (struct device_info *)(payload + 1 +
149                                         sizeof(struct device_info) * i);
150                                 if (client_data->hid_devices)
151                                         memcpy(client_data->hid_devices + i,
152                                                dev_info,
153                                                sizeof(struct device_info));
154                         }
155
156                         client_data->enum_devices_done = true;
157                         wake_up_interruptible(&client_data->init_wait);
158
159                         break;
160
161                 case HOSTIF_GET_HID_DESCRIPTOR:
162                         if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
163                                         client_data->init_done)) {
164                                 ++client_data->bad_recv_cnt;
165                                 report_bad_packet(hid_ishtp_cl, recv_msg,
166                                                   cur_pos,
167                                                   payload_len);
168                                 ish_hw_reset(hid_ishtp_cl->dev);
169                                 break;
170                         }
171                         if (!client_data->hid_descr[curr_hid_dev])
172                                 client_data->hid_descr[curr_hid_dev] =
173                                 devm_kmalloc(&client_data->cl_device->dev,
174                                              payload_len, GFP_KERNEL);
175                         if (client_data->hid_descr[curr_hid_dev]) {
176                                 memcpy(client_data->hid_descr[curr_hid_dev],
177                                        payload, payload_len);
178                                 client_data->hid_descr_size[curr_hid_dev] =
179                                         payload_len;
180                                 client_data->hid_descr_done = true;
181                         }
182                         wake_up_interruptible(&client_data->init_wait);
183
184                         break;
185
186                 case HOSTIF_GET_REPORT_DESCRIPTOR:
187                         if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
188                                         client_data->init_done)) {
189                                 ++client_data->bad_recv_cnt;
190                                 report_bad_packet(hid_ishtp_cl, recv_msg,
191                                                   cur_pos,
192                                                   payload_len);
193                                 ish_hw_reset(hid_ishtp_cl->dev);
194                                 break;
195                         }
196                         if (!client_data->report_descr[curr_hid_dev])
197                                 client_data->report_descr[curr_hid_dev] =
198                                 devm_kmalloc(&client_data->cl_device->dev,
199                                              payload_len, GFP_KERNEL);
200                         if (client_data->report_descr[curr_hid_dev])  {
201                                 memcpy(client_data->report_descr[curr_hid_dev],
202                                        payload,
203                                        payload_len);
204                                 client_data->report_descr_size[curr_hid_dev] =
205                                         payload_len;
206                                 client_data->report_descr_done = true;
207                         }
208                         wake_up_interruptible(&client_data->init_wait);
209
210                         break;
211
212                 case HOSTIF_GET_FEATURE_REPORT:
213                         report_type = HID_FEATURE_REPORT;
214                         goto    do_get_report;
215
216                 case HOSTIF_GET_INPUT_REPORT:
217                         report_type = HID_INPUT_REPORT;
218 do_get_report:
219                         /* Get index of device that matches this id */
220                         for (i = 0; i < client_data->num_hid_devices; ++i) {
221                                 if (recv_msg->hdr.device_id ==
222                                         client_data->hid_devices[i].dev_id)
223                                         if (client_data->hid_sensor_hubs[i]) {
224                                                 hid_input_report(
225                                                 client_data->hid_sensor_hubs[
226                                                                         i],
227                                                 report_type, payload,
228                                                 payload_len, 0);
229                                                 ishtp_hid_wakeup(
230                                                 client_data->hid_sensor_hubs[
231                                                         i]);
232                                                 break;
233                                         }
234                         }
235                         break;
236
237                 case HOSTIF_SET_FEATURE_REPORT:
238                         /* Get index of device that matches this id */
239                         for (i = 0; i < client_data->num_hid_devices; ++i) {
240                                 if (recv_msg->hdr.device_id ==
241                                         client_data->hid_devices[i].dev_id)
242                                         if (client_data->hid_sensor_hubs[i]) {
243                                                 ishtp_hid_wakeup(
244                                                 client_data->hid_sensor_hubs[
245                                                         i]);
246                                                 break;
247                                         }
248                         }
249                         break;
250
251                 case HOSTIF_PUBLISH_INPUT_REPORT:
252                         report_type = HID_INPUT_REPORT;
253                         for (i = 0; i < client_data->num_hid_devices; ++i)
254                                 if (recv_msg->hdr.device_id ==
255                                         client_data->hid_devices[i].dev_id)
256                                         if (client_data->hid_sensor_hubs[i])
257                                                 hid_input_report(
258                                                 client_data->hid_sensor_hubs[
259                                                                         i],
260                                                 report_type, payload,
261                                                 payload_len, 0);
262                         break;
263
264                 case HOSTIF_PUBLISH_INPUT_REPORT_LIST:
265                         report_type = HID_INPUT_REPORT;
266                         reports_list = (struct report_list *)payload;
267                         reports = (char *)reports_list->reports;
268
269                         for (j = 0; j < reports_list->num_of_reports; j++) {
270                                 recv_msg = (struct hostif_msg *)(reports +
271                                         sizeof(uint16_t));
272                                 report_len = *(uint16_t *)reports;
273                                 payload = reports + sizeof(uint16_t) +
274                                         sizeof(struct hostif_msg_hdr);
275                                 payload_len = report_len -
276                                         sizeof(struct hostif_msg_hdr);
277
278                                 for (i = 0; i < client_data->num_hid_devices;
279                                      ++i)
280                                         if (recv_msg->hdr.device_id ==
281                                         client_data->hid_devices[i].dev_id &&
282                                         client_data->hid_sensor_hubs[i]) {
283                                                 hid_input_report(
284                                                 client_data->hid_sensor_hubs[
285                                                                         i],
286                                                 report_type,
287                                                 payload, payload_len,
288                                                 0);
289                                         }
290
291                                 reports += sizeof(uint16_t) + report_len;
292                         }
293                         break;
294                 default:
295                         ++client_data->bad_recv_cnt;
296                         report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
297                                           payload_len);
298                         ish_hw_reset(hid_ishtp_cl->dev);
299                         break;
300
301                 }
302
303                 if (!cur_pos && cur_pos + payload_len +
304                                 sizeof(struct hostif_msg) < total_len)
305                         ++client_data->multi_packet_cnt;
306
307                 cur_pos += payload_len + sizeof(struct hostif_msg);
308                 payload += payload_len + sizeof(struct hostif_msg);
309
310         } while (cur_pos < total_len);
311 }
312
313 /**
314  * ish_cl_event_cb() - bus driver callback for incoming message/packet
315  * @device:     Pointer to the the ishtp client device for which this message
316  *              is targeted
317  *
318  * Remove the packet from the list and process the message by calling
319  * process_recv
320  */
321 static void ish_cl_event_cb(struct ishtp_cl_device *device)
322 {
323         struct ishtp_cl *hid_ishtp_cl = device->driver_data;
324         struct ishtp_cl_rb *rb_in_proc;
325         size_t r_length;
326         unsigned long flags;
327
328         if (!hid_ishtp_cl)
329                 return;
330
331         spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
332         while (!list_empty(&hid_ishtp_cl->in_process_list.list)) {
333                 rb_in_proc = list_entry(
334                         hid_ishtp_cl->in_process_list.list.next,
335                         struct ishtp_cl_rb, list);
336                 list_del_init(&rb_in_proc->list);
337                 spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock,
338                         flags);
339
340                 if (!rb_in_proc->buffer.data)
341                         return;
342
343                 r_length = rb_in_proc->buf_idx;
344
345                 /* decide what to do with received data */
346                 process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);
347
348                 ishtp_cl_io_rb_recycle(rb_in_proc);
349                 spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
350         }
351         spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, flags);
352 }
353
354 /**
355  * hid_ishtp_set_feature() - send request to ISH FW to set a feature request
356  * @hid:        hid device instance for this request
357  * @buf:        feature buffer
358  * @len:        Length of feature buffer
359  * @report_id:  Report id for the feature set request
360  *
361  * This is called from hid core .request() callback. This function doesn't wait
362  * for response.
363  */
364 void hid_ishtp_set_feature(struct hid_device *hid, char *buf, unsigned int len,
365                            int report_id)
366 {
367         struct ishtp_hid_data *hid_data =  hid->driver_data;
368         struct ishtp_cl_data *client_data = hid_data->client_data;
369         struct hostif_msg *msg = (struct hostif_msg *)buf;
370         int     rv;
371         int     i;
372
373         hid_ishtp_trace(client_data,  "%s hid %p\n", __func__, hid);
374
375         rv = ishtp_hid_link_ready_wait(client_data);
376         if (rv) {
377                 hid_ishtp_trace(client_data,  "%s hid %p link not ready\n",
378                                 __func__, hid);
379                 return;
380         }
381
382         memset(msg, 0, sizeof(struct hostif_msg));
383         msg->hdr.command = HOSTIF_SET_FEATURE_REPORT;
384         for (i = 0; i < client_data->num_hid_devices; ++i) {
385                 if (hid == client_data->hid_sensor_hubs[i]) {
386                         msg->hdr.device_id =
387                                 client_data->hid_devices[i].dev_id;
388                         break;
389                 }
390         }
391
392         if (i == client_data->num_hid_devices)
393                 return;
394
395         rv = ishtp_cl_send(client_data->hid_ishtp_cl, buf, len);
396         if (rv)
397                 hid_ishtp_trace(client_data,  "%s hid %p send failed\n",
398                                 __func__, hid);
399 }
400
401 /**
402  * hid_ishtp_get_report() - request to get feature/input report
403  * @hid:        hid device instance for this request
404  * @report_id:  Report id for the get request
405  * @report_type:        Report type for the this request
406  *
407  * This is called from hid core .request() callback. This function will send
408  * request to FW and return without waiting for response.
409  */
410 void hid_ishtp_get_report(struct hid_device *hid, int report_id,
411                           int report_type)
412 {
413         struct ishtp_hid_data *hid_data =  hid->driver_data;
414         struct ishtp_cl_data *client_data = hid_data->client_data;
415         struct hostif_msg_to_sensor msg = {};
416         int     rv;
417         int     i;
418
419         hid_ishtp_trace(client_data,  "%s hid %p\n", __func__, hid);
420         rv = ishtp_hid_link_ready_wait(client_data);
421         if (rv) {
422                 hid_ishtp_trace(client_data,  "%s hid %p link not ready\n",
423                                 __func__, hid);
424                 return;
425         }
426
427         msg.hdr.command = (report_type == HID_FEATURE_REPORT) ?
428                 HOSTIF_GET_FEATURE_REPORT : HOSTIF_GET_INPUT_REPORT;
429         for (i = 0; i < client_data->num_hid_devices; ++i) {
430                 if (hid == client_data->hid_sensor_hubs[i]) {
431                         msg.hdr.device_id =
432                                 client_data->hid_devices[i].dev_id;
433                         break;
434                 }
435         }
436
437         if (i == client_data->num_hid_devices)
438                 return;
439
440         msg.report_id = report_id;
441         rv = ishtp_cl_send(client_data->hid_ishtp_cl, (uint8_t *)&msg,
442                             sizeof(msg));
443         if (rv)
444                 hid_ishtp_trace(client_data,  "%s hid %p send failed\n",
445                                 __func__, hid);
446 }
447
448 /**
449  * ishtp_hid_link_ready_wait() - Wait for link ready
450  * @client_data:        client data instance
451  *
452  * If the transport link started suspend process, then wait, till either
453  * resumed or timeout
454  *
455  * Return: 0 on success, non zero on error
456  */
457 int ishtp_hid_link_ready_wait(struct ishtp_cl_data *client_data)
458 {
459         int rc;
460
461         if (client_data->suspended) {
462                 hid_ishtp_trace(client_data,  "wait for link ready\n");
463                 rc = wait_event_interruptible_timeout(
464                                         client_data->ishtp_resume_wait,
465                                         !client_data->suspended,
466                                         5 * HZ);
467
468                 if (rc == 0) {
469                         hid_ishtp_trace(client_data,  "link not ready\n");
470                         return -EIO;
471                 }
472                 hid_ishtp_trace(client_data,  "link ready\n");
473         }
474
475         return 0;
476 }
477
478 /**
479  * ishtp_enum_enum_devices() - Enumerate hid devices
480  * @hid_ishtp_cl:       client instance
481  *
482  * Helper function to send request to firmware to enumerate HID devices
483  *
484  * Return: 0 on success, non zero on error
485  */
486 static int ishtp_enum_enum_devices(struct ishtp_cl *hid_ishtp_cl)
487 {
488         struct hostif_msg msg;
489         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
490         int retry_count;
491         int rv;
492
493         /* Send HOSTIF_DM_ENUM_DEVICES */
494         memset(&msg, 0, sizeof(struct hostif_msg));
495         msg.hdr.command = HOSTIF_DM_ENUM_DEVICES;
496         rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *)&msg,
497                            sizeof(struct hostif_msg));
498         if (rv)
499                 return rv;
500
501         retry_count = 0;
502         while (!client_data->enum_devices_done &&
503                retry_count < 10) {
504                 wait_event_interruptible_timeout(client_data->init_wait,
505                                          client_data->enum_devices_done,
506                                          3 * HZ);
507                 ++retry_count;
508                 if (!client_data->enum_devices_done)
509                         /* Send HOSTIF_DM_ENUM_DEVICES */
510                         rv = ishtp_cl_send(hid_ishtp_cl,
511                                            (unsigned char *) &msg,
512                                            sizeof(struct hostif_msg));
513         }
514         if (!client_data->enum_devices_done) {
515                 dev_err(&client_data->cl_device->dev,
516                         "[hid-ish]: timed out waiting for enum_devices\n");
517                 return -ETIMEDOUT;
518         }
519         if (!client_data->hid_devices) {
520                 dev_err(&client_data->cl_device->dev,
521                         "[hid-ish]: failed to allocate HID dev structures\n");
522                 return -ENOMEM;
523         }
524
525         client_data->num_hid_devices = client_data->hid_dev_count;
526         dev_info(&hid_ishtp_cl->device->dev,
527                 "[hid-ish]: enum_devices_done OK, num_hid_devices=%d\n",
528                 client_data->num_hid_devices);
529
530         return  0;
531 }
532
533 /**
534  * ishtp_get_hid_descriptor() - Get hid descriptor
535  * @hid_ishtp_cl:       client instance
536  * @index:              Index into the hid_descr array
537  *
538  * Helper function to send request to firmware get HID descriptor of a device
539  *
540  * Return: 0 on success, non zero on error
541  */
542 static int ishtp_get_hid_descriptor(struct ishtp_cl *hid_ishtp_cl, int index)
543 {
544         struct hostif_msg msg;
545         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
546         int rv;
547
548         /* Get HID descriptor */
549         client_data->hid_descr_done = false;
550         memset(&msg, 0, sizeof(struct hostif_msg));
551         msg.hdr.command = HOSTIF_GET_HID_DESCRIPTOR;
552         msg.hdr.device_id = client_data->hid_devices[index].dev_id;
553         rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
554                            sizeof(struct hostif_msg));
555         if (rv)
556                 return rv;
557
558         if (!client_data->hid_descr_done) {
559                 wait_event_interruptible_timeout(client_data->init_wait,
560                                                  client_data->hid_descr_done,
561                                                  3 * HZ);
562                 if (!client_data->hid_descr_done) {
563                         dev_err(&client_data->cl_device->dev,
564                                 "[hid-ish]: timed out for hid_descr_done\n");
565                         return -EIO;
566                 }
567
568                 if (!client_data->hid_descr[index]) {
569                         dev_err(&client_data->cl_device->dev,
570                                 "[hid-ish]: allocation HID desc fail\n");
571                         return -ENOMEM;
572                 }
573         }
574
575         return 0;
576 }
577
578 /**
579  * ishtp_get_report_descriptor() - Get report descriptor
580  * @hid_ishtp_cl:       client instance
581  * @index:              Index into the hid_descr array
582  *
583  * Helper function to send request to firmware get HID report descriptor of
584  * a device
585  *
586  * Return: 0 on success, non zero on error
587  */
588 static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
589                                        int index)
590 {
591         struct hostif_msg msg;
592         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
593         int rv;
594
595         /* Get report descriptor */
596         client_data->report_descr_done = false;
597         memset(&msg, 0, sizeof(struct hostif_msg));
598         msg.hdr.command = HOSTIF_GET_REPORT_DESCRIPTOR;
599         msg.hdr.device_id = client_data->hid_devices[index].dev_id;
600         rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
601                            sizeof(struct hostif_msg));
602         if (rv)
603                 return rv;
604
605         if (!client_data->report_descr_done)
606                 wait_event_interruptible_timeout(client_data->init_wait,
607                                          client_data->report_descr_done,
608                                          3 * HZ);
609         if (!client_data->report_descr_done) {
610                 dev_err(&client_data->cl_device->dev,
611                                 "[hid-ish]: timed out for report descr\n");
612                 return -EIO;
613         }
614         if (!client_data->report_descr[index]) {
615                 dev_err(&client_data->cl_device->dev,
616                         "[hid-ish]: failed to alloc report descr\n");
617                 return -ENOMEM;
618         }
619
620         return 0;
621 }
622
623 /**
624  * hid_ishtp_cl_init() - Init function for ISHTP client
625  * @hid_ishtp_cl:       ISHTP client instance
626  * @reset:              true if called for init after reset
627  *
628  * This function complete the initializtion of the client. The summary of
629  * processing:
630  * - Send request to enumerate the hid clients
631  *      Get the HID descriptor for each enumearated device
632  *      Get report description of each device
633  *      Register each device wik hid core by calling ishtp_hid_probe
634  *
635  * Return: 0 on success, non zero on error
636  */
637 static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
638 {
639         struct ishtp_device *dev;
640         unsigned long flags;
641         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
642         int i;
643         int rv;
644
645         dev_dbg(&client_data->cl_device->dev, "%s\n", __func__);
646         hid_ishtp_trace(client_data,  "%s reset flag: %d\n", __func__, reset);
647
648         rv = ishtp_cl_link(hid_ishtp_cl, ISHTP_HOST_CLIENT_ID_ANY);
649         if (rv) {
650                 dev_err(&client_data->cl_device->dev,
651                         "ishtp_cl_link failed\n");
652                 return  -ENOMEM;
653         }
654
655         client_data->init_done = 0;
656
657         dev = hid_ishtp_cl->dev;
658
659         /* Connect to FW client */
660         hid_ishtp_cl->rx_ring_size = HID_CL_RX_RING_SIZE;
661         hid_ishtp_cl->tx_ring_size = HID_CL_TX_RING_SIZE;
662
663         spin_lock_irqsave(&dev->fw_clients_lock, flags);
664         i = ishtp_fw_cl_by_uuid(dev, &hid_ishtp_guid);
665         if (i < 0) {
666                 spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
667                 dev_err(&client_data->cl_device->dev,
668                         "ish client uuid not found\n");
669                 return i;
670         }
671         hid_ishtp_cl->fw_client_id = dev->fw_clients[i].client_id;
672         spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
673         hid_ishtp_cl->state = ISHTP_CL_CONNECTING;
674
675         rv = ishtp_cl_connect(hid_ishtp_cl);
676         if (rv) {
677                 dev_err(&client_data->cl_device->dev,
678                         "client connect fail\n");
679                 goto err_cl_unlink;
680         }
681
682         hid_ishtp_trace(client_data,  "%s client connected\n", __func__);
683
684         /* Register read callback */
685         ishtp_register_event_cb(hid_ishtp_cl->device, ish_cl_event_cb);
686
687         rv = ishtp_enum_enum_devices(hid_ishtp_cl);
688         if (rv)
689                 goto err_cl_disconnect;
690
691         hid_ishtp_trace(client_data,  "%s enumerated device count %d\n",
692                         __func__, client_data->num_hid_devices);
693
694         for (i = 0; i < client_data->num_hid_devices; ++i) {
695                 client_data->cur_hid_dev = i;
696
697                 rv = ishtp_get_hid_descriptor(hid_ishtp_cl, i);
698                 if (rv)
699                         goto err_cl_disconnect;
700
701                 rv = ishtp_get_report_descriptor(hid_ishtp_cl, i);
702                 if (rv)
703                         goto err_cl_disconnect;
704
705                 if (!reset) {
706                         rv = ishtp_hid_probe(i, client_data);
707                         if (rv) {
708                                 dev_err(&client_data->cl_device->dev,
709                                 "[hid-ish]: HID probe for #%u failed: %d\n",
710                                 i, rv);
711                                 goto err_cl_disconnect;
712                         }
713                 }
714         } /* for() on all hid devices */
715
716         client_data->init_done = 1;
717         client_data->suspended = false;
718         wake_up_interruptible(&client_data->ishtp_resume_wait);
719         hid_ishtp_trace(client_data,  "%s successful init\n", __func__);
720         return 0;
721
722 err_cl_disconnect:
723         hid_ishtp_cl->state = ISHTP_CL_DISCONNECTING;
724         ishtp_cl_disconnect(hid_ishtp_cl);
725 err_cl_unlink:
726         ishtp_cl_unlink(hid_ishtp_cl);
727         return rv;
728 }
729
730 /**
731  * hid_ishtp_cl_deinit() - Deinit function for ISHTP client
732  * @hid_ishtp_cl:       ISHTP client instance
733  *
734  * Unlink and free hid client
735  */
736 static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl)
737 {
738         ishtp_cl_unlink(hid_ishtp_cl);
739         ishtp_cl_flush_queues(hid_ishtp_cl);
740
741         /* disband and free all Tx and Rx client-level rings */
742         ishtp_cl_free(hid_ishtp_cl);
743 }
744
745 static void hid_ishtp_cl_reset_handler(struct work_struct *work)
746 {
747         struct ishtp_cl_data *client_data;
748         struct ishtp_cl *hid_ishtp_cl;
749         struct ishtp_cl_device *cl_device;
750         int retry;
751         int rv;
752
753         client_data = container_of(work, struct ishtp_cl_data, work);
754
755         hid_ishtp_cl = client_data->hid_ishtp_cl;
756         cl_device = client_data->cl_device;
757
758         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
759                         hid_ishtp_cl);
760         dev_dbg(&cl_device->dev, "%s\n", __func__);
761
762         hid_ishtp_cl_deinit(hid_ishtp_cl);
763
764         hid_ishtp_cl = ishtp_cl_allocate(cl_device->ishtp_dev);
765         if (!hid_ishtp_cl)
766                 return;
767
768         cl_device->driver_data = hid_ishtp_cl;
769         hid_ishtp_cl->client_data = client_data;
770         client_data->hid_ishtp_cl = hid_ishtp_cl;
771
772         client_data->num_hid_devices = 0;
773
774         for (retry = 0; retry < 3; ++retry) {
775                 rv = hid_ishtp_cl_init(hid_ishtp_cl, 1);
776                 if (!rv)
777                         break;
778                 dev_err(&client_data->cl_device->dev, "Retry reset init\n");
779         }
780         if (rv) {
781                 dev_err(&client_data->cl_device->dev, "Reset Failed\n");
782                 hid_ishtp_trace(client_data, "%s Failed hid_ishtp_cl %p\n",
783                                 __func__, hid_ishtp_cl);
784         }
785 }
786
787 /**
788  * hid_ishtp_cl_probe() - ISHTP client driver probe
789  * @cl_device:          ISHTP client device instance
790  *
791  * This function gets called on device create on ISHTP bus
792  *
793  * Return: 0 on success, non zero on error
794  */
795 static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
796 {
797         struct ishtp_cl *hid_ishtp_cl;
798         struct ishtp_cl_data *client_data;
799         int rv;
800
801         if (!cl_device)
802                 return  -ENODEV;
803
804         if (uuid_le_cmp(hid_ishtp_guid,
805                         cl_device->fw_client->props.protocol_name) != 0)
806                 return  -ENODEV;
807
808         client_data = devm_kzalloc(&cl_device->dev, sizeof(*client_data),
809                                    GFP_KERNEL);
810         if (!client_data)
811                 return -ENOMEM;
812
813         hid_ishtp_cl = ishtp_cl_allocate(cl_device->ishtp_dev);
814         if (!hid_ishtp_cl)
815                 return -ENOMEM;
816
817         cl_device->driver_data = hid_ishtp_cl;
818         hid_ishtp_cl->client_data = client_data;
819         client_data->hid_ishtp_cl = hid_ishtp_cl;
820         client_data->cl_device = cl_device;
821
822         init_waitqueue_head(&client_data->init_wait);
823         init_waitqueue_head(&client_data->ishtp_resume_wait);
824
825         INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
826
827         rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
828         if (rv) {
829                 ishtp_cl_free(hid_ishtp_cl);
830                 return rv;
831         }
832         ishtp_get_device(cl_device);
833
834         return 0;
835 }
836
837 /**
838  * hid_ishtp_cl_remove() - ISHTP client driver remove
839  * @cl_device:          ISHTP client device instance
840  *
841  * This function gets called on device remove on ISHTP bus
842  *
843  * Return: 0
844  */
845 static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
846 {
847         struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
848         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
849
850         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
851                         hid_ishtp_cl);
852
853         dev_dbg(&cl_device->dev, "%s\n", __func__);
854         hid_ishtp_cl->state = ISHTP_CL_DISCONNECTING;
855         ishtp_cl_disconnect(hid_ishtp_cl);
856         ishtp_put_device(cl_device);
857         ishtp_hid_remove(client_data);
858         hid_ishtp_cl_deinit(hid_ishtp_cl);
859
860         hid_ishtp_cl = NULL;
861
862         client_data->num_hid_devices = 0;
863
864         return 0;
865 }
866
867 /**
868  * hid_ishtp_cl_reset() - ISHTP client driver reset
869  * @cl_device:          ISHTP client device instance
870  *
871  * This function gets called on device reset on ISHTP bus
872  *
873  * Return: 0
874  */
875 static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
876 {
877         struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
878         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
879
880         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
881                         hid_ishtp_cl);
882
883         schedule_work(&client_data->work);
884
885         return 0;
886 }
887
888 #define to_ishtp_cl_device(d) container_of(d, struct ishtp_cl_device, dev)
889
890 /**
891  * hid_ishtp_cl_suspend() - ISHTP client driver suspend
892  * @device:     device instance
893  *
894  * This function gets called on system suspend
895  *
896  * Return: 0
897  */
898 static int hid_ishtp_cl_suspend(struct device *device)
899 {
900         struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
901         struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
902         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
903
904         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
905                         hid_ishtp_cl);
906         client_data->suspended = true;
907
908         return 0;
909 }
910
911 /**
912  * hid_ishtp_cl_resume() - ISHTP client driver resume
913  * @device:     device instance
914  *
915  * This function gets called on system resume
916  *
917  * Return: 0
918  */
919 static int hid_ishtp_cl_resume(struct device *device)
920 {
921         struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
922         struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
923         struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
924
925         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
926                         hid_ishtp_cl);
927         client_data->suspended = false;
928         return 0;
929 }
930
931 static const struct dev_pm_ops hid_ishtp_pm_ops = {
932         .suspend = hid_ishtp_cl_suspend,
933         .resume = hid_ishtp_cl_resume,
934 };
935
936 static struct ishtp_cl_driver   hid_ishtp_cl_driver = {
937         .name = "ish-hid",
938         .probe = hid_ishtp_cl_probe,
939         .remove = hid_ishtp_cl_remove,
940         .reset = hid_ishtp_cl_reset,
941         .driver.pm = &hid_ishtp_pm_ops,
942 };
943
944 static int __init ish_hid_init(void)
945 {
946         int     rv;
947
948         /* Register ISHTP client device driver with ISHTP Bus */
949         rv = ishtp_cl_driver_register(&hid_ishtp_cl_driver);
950
951         return rv;
952
953 }
954
955 static void __exit ish_hid_exit(void)
956 {
957         ishtp_cl_driver_unregister(&hid_ishtp_cl_driver);
958 }
959
960 late_initcall(ish_hid_init);
961 module_exit(ish_hid_exit);
962
963 MODULE_DESCRIPTION("ISH ISHTP HID client driver");
964 /* Primary author */
965 MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
966 /*
967  * Several modification for multi instance support
968  * suspend/resume and clean up
969  */
970 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
971
972 MODULE_LICENSE("GPL");
973 MODULE_ALIAS("ishtp:*");