#include #include #include #include #include #include #include #include struct nunchuk_dev { struct input_polled_dev *polled_input; struct i2c_client *i2c_client; }; static int handle_error(int ret) { printk("Nunchuk Error handled : %d", ret); return (0); } static char *nunchuk_read_registers(struct i2c_client *client, int size) { char buff[6] = {0x00}; int ret = 0; char *buffi; buffi = kmalloc(size, GFP_KERNEL); mdelay(10); if ((ret = i2c_master_send(client, buff, 1)) < 0) { handle_error(ret); return (NULL); } mdelay(10); if ((ret = i2c_master_recv(client, buffi, 6)) < 0) { handle_error(ret); return (NULL); } return (buffi); } void nunchuk_poll(struct input_polled_dev *dev) { int cPressed = 0, zPressed = 0; char *buff_ret; struct nunchuk_dev *nunchuk; char coordX, coordY; char ax, ay, az; nunchuk = dev->private; /* Read data provided by nunchuk */ buff_ret = nunchuk_read_registers(nunchuk->i2c_client, 6); zPressed = !((buff_ret[5] & 0x1)); cPressed = !((buff_ret[5] & 0x2) >> 1); coordX = buff_ret[0]; coordY = buff_ret[1]; ax = (buff_ret[2] << 2) & ((buff_ret[5] >> 2) & 0x3); ay = (buff_ret[3] << 2) & ((buff_ret[5] >> 4) & 0x3); az = (buff_ret[4] << 2) & ((buff_ret[5] >> 6) & 0x3); /* Notify new event */ input_event(nunchuk->polled_input->input, EV_KEY, BTN_Z, zPressed); input_event(nunchuk->polled_input->input, EV_KEY, BTN_C, cPressed); input_event(nunchuk->polled_input->input, EV_ABS, ABS_X, coordX); input_event(nunchuk->polled_input->input, EV_ABS, ABS_Y, coordY); input_event(nunchuk->polled_input->input, EV_ABS, ABS_RX, ax); input_event(nunchuk->polled_input->input, EV_ABS, ABS_RY, ax); input_event(nunchuk->polled_input->input, EV_ABS, ABS_RZ, ay); input_sync(nunchuk->polled_input->input); kfree(buff_ret); } static int nunchuk_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; char buff[] = {0xF0, 0x55}; struct input_polled_dev *polled_input; struct input_dev *input; struct nunchuk_dev *nunchuk; polled_input = input_allocate_polled_device(); if (!(nunchuk = devm_kzalloc(&client->dev, sizeof(struct nunchuk_dev), GFP_KERNEL))) { dev_err(&client->dev, "Failed to allocate memory\n"); return (-ENOMEM); } if ((ret = i2c_master_send(client, buff, 2)) < 0) //Send initialization frame to device return (handle_error(ret)); udelay(1000); /* Second initialization */ buff[0] = 0xFB; buff[1] = 0x00; if ((ret = i2c_master_send(client, buff, 2)) < 0) return (handle_error(ret)); nunchuk->i2c_client = client; nunchuk->polled_input = polled_input; polled_input->private = nunchuk; i2c_set_clientdata(client, nunchuk); input = polled_input->input; input->dev.parent = &(client->dev); input->name = "Wii Nunchuk"; input->id.bustype = BUS_I2C; /* Set input events for buttons */ set_bit(EV_KEY, input->evbit); set_bit(BTN_C, input->keybit); set_bit(BTN_Z, input->keybit); /* Set input events for joystick */ set_bit(EV_ABS, input->evbit); set_bit(ABS_X, input->keybit); set_bit(ABS_Y, input->keybit); set_bit(ABS_RX, input->keybit); set_bit(ABS_RY, input->keybit); set_bit(ABS_RZ, input->keybit); input_set_abs_params(input, ABS_X, 0, 255, 2, 4); input_set_abs_params(input, ABS_Y, 0, 255, 2, 4); input_set_abs_params(input, ABS_RX, 0, 0x3ff, 4, 8); input_set_abs_params(input, ABS_RY, 0, 0x3ff, 4, 8); input_set_abs_params(input, ABS_RZ, 0, 0x3ff, 4, 8); polled_input->poll = nunchuk_poll; polled_input->poll_interval = 50; if ((ret = input_register_polled_device(polled_input))) { pr_info("Error while registering polled_input.../n"); input_free_polled_device(polled_input); return (0); } return (0); } static int nunchuk_remove(struct i2c_client *client) { struct nunchuk_dev *nunchuk; nunchuk = i2c_get_clientdata(client); input_unregister_polled_device(nunchuk->polled_input); input_free_polled_device(nunchuk->polled_input); pr_info("Nunchuk Module removed\n"); return (0); } static const struct i2c_device_id nunchuk_id[] = { { "nunchuk", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, nunchuk_id); static const struct of_device_id nunchuk_dt_ids[] = { { .compatible = "nitendo,nunchuk", }, //Allow to identify our nunchuk by it compatible string { } }; MODULE_DEVICE_TABLE(of, nunchuk_dt_ids); static struct i2c_driver nunchuk_driver = { .probe = nunchuk_probe, //Handler for device detection .remove = nunchuk_remove, //Handler for module deletion .id_table = nunchuk_id, .driver = { .name = "nunchuk", .owner = THIS_MODULE, .of_match_table = of_match_ptr(nunchuk_dt_ids), }, }; module_i2c_driver(nunchuk_driver); //Register our driver Kernel side MODULE_LICENSE("GPL");