g_hid loading unloading crash

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Dear all,
I was trying to do a stress test on module insertion and removal. 1st
time modprobe g_hid and rmmod g_hid works. second time when doing
insmod g_hid crashes the core.

crash trace
----------------

root@imx6ulevk:~# modprobe ci_hdrc ci_hdrc.0: Device No Response
g_hid
Unable to handle kernel paging request at virtual address 7f09b664
pgd = 88a78000
[7f09b664] *pgd=88576811, *pte=00000000, *ppte=00000000
Internal error: Oops: 807 [#1] PREEMPT SMP ARM
Modules linked in: g_hid(+) usb_f_hid libcomposite configfs
ci_hdrc_imx usbmisc_imx ci_hdrc evbug uio_pdrv_genirq uio [last
unloaded: g_hid]
CPU: 0 PID: 679 Comm: modprobe Not tainted 4.1.15-2.1.0+g30278ab #31
Hardware name: Freescale i.MX6 Ultralite (Device Tree)
task: 88434980 ti: 88ac2000 task.ti: 88ac2000
PC is at kobject_add_internal+0x78/0x2f0
LR is at preempt_count_add+0x98/0x134
pc : [<802b5a88>]    lr : [<80053f44>]    psr: 60010013
sp : 88ac3d98  ip : 00000000  fp : 00000124
r10: 77b2bedc  r9 : 00000001  r8 : 00000000
r7 : 80bb2ed0  r6 : 00000000  r5 : 80bb2ed0  r4 : 7f0a7660
r3 : 7f0a7664  r2 : 8801fbc0  r1 : 7f09b664  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c53c7d  Table: 88a7806a  DAC: 00000015
Process modprobe (pid: 679, stack limit = 0x88ac2210)
Stack: (0x88ac3d98 to 0x88ac4000)
3d80:                                                       00000124 88ac3e08
3da0: 00000007 80b84240 7f0a7660 7f0a7660 80bb2ed0 00000000 00000000 802b5d48
3dc0: 88595180 88ac3ddc 7f0a7660 7f0a7658 80bb2ec8 80388154 00000000 00000000
3de0: 80b89720 7f0a7648 88595180 7f0a7658 00000000 7f0a7648 88595180 7f0a7658
3e00: 00000000 00000001 77b2bedc 8038c03c 80b89720 80b89720 88595180 7f0aa000
3e20: 00000000 7f0aa00c 80b89720 80009718 8bc6bfa0 800e856c 00000003 88a7dfc0
3e40: 8040003e 00000001 00080000 800b6200 00000003 8040003e 8bc60a60 8bc6bfa0
3e60: 80b866bc 80b84230 88001f00 80b866bc 00000124 800e9d44 7f0a7958 00000001
3e80: 7f0a7958 00000001 88595280 7f0a7958 884d4140 807f228c 7f0a7958 884d4140
3ea0: 88ac3f58 00000001 884d4148 8009690c 7f0a7964 00007fff 8009394c 00000000
3ec0: 00000000 7f0a79a0 00000000 7f0a7aa0 a0b88bf8 7f0a7964 00000000 807ffa5c
3ee0: a0b86000 00002c48 0000007a 00000000 0b300002 00000000 00000000 00000000
3f00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
3f20: 00000000 00000000 00000000 00000000 00000018 00000000 00000003 00027cc0
3f40: 0000017b 8000f604 88ac2000 00000000 01d98dd0 80096d70 a0b86000 00002c48
3f60: a0b88720 a0b885d0 a0b87c20 00000acc 00000e0c 00000000 00000000 00000000
3f80: 0000001f 00000020 00000016 0000001a 00000011 00000000 00000000 000393a8
3fa0: 00000000 8000f480 00000000 000393a8 00000003 00027cc0 00000000 01d98db0
3fc0: 00000000 000393a8 00000000 0000017b 01d98e30 00000000 000393a8 01d98dd0
3fe0: 7ed0d9f0 7ed0d9e0 0001f2a4 76e5db60 60070010 00000003 00000010 00000628
[<802b5a88>] (kobject_add_internal) from [<802b5d48>] (kobject_add+0x48/0x94)
[<802b5d48>] (kobject_add) from [<80388154>] (device_add+0xd8/0x56c)
[<80388154>] (device_add) from [<8038c03c>] (platform_device_add+0x110/0x220)
[<8038c03c>] (platform_device_add) from [<7f0aa00c>]
(hidg_init+0xc/0x7c [g_hid])
[<7f0aa00c>] (hidg_init [g_hid]) from [<80009718>] (do_one_initcall+0x8c/0x1d4)
[<80009718>] (do_one_initcall) from [<807f228c>] (do_init_module+0x5c/0x1a8)
[<807f228c>] (do_init_module) from [<8009690c>] (load_module+0x1ba8/0x1e50)
[<8009690c>] (load_module) from [<80096d70>] (SyS_finit_module+0x80/0x90)
[<80096d70>] (SyS_finit_module) from [<8000f480>] (ret_fast_syscall+0x0/0x3c)
Code: e5921004 e5823004 e5842004 e5841008 (e5813000)
---[ end trace 4155b283fc24e686 ]---
note: modprobe[679] exited with preempt_count 1
Segmentation fault

kindly help
/*
 * hid.c -- HID Composite driver
 *
 * Based on multi.c
 *
 * Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@xxxxxxxxx>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */


#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/usb/composite.h>
#include <linux/usb/g_hid.h>

#include "gadget_chips.h"
#define DRIVER_DESC		"HID Gadget"
#define DRIVER_VERSION		"2010/03/16"

#include "u_hid.h"

/*-------------------------------------------------------------------------*/

#define HIDG_VENDOR_NUM		0x0483
#define HIDG_PRODUCT_NUM	0xA1F8

/*-------------------------------------------------------------------------*/

struct hidg_func_node {
	struct list_head node;
	struct usb_function_instance *fi;
	struct usb_function *f;
	struct hidg_func_descriptor *func;
};

static LIST_HEAD(hidg_func_list);

/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();

static struct usb_device_descriptor device_desc = {
	.bLength =		sizeof device_desc,
	.bDescriptorType =	1,

	.bcdUSB =		cpu_to_le16(0x0200),

	/* .bDeviceClass =		USB_CLASS_COMM, */
	/* .bDeviceSubClass =	0, */
	/* .bDeviceProtocol =	0, */
	.bDeviceClass =		3,
	.bDeviceSubClass =	0,
	.bDeviceProtocol =	0,
	.bMaxPacketSize0 =	64,

	/* Vendor and product id can be overridden by module parameters.  */
	.idVendor =		cpu_to_le16(HIDG_VENDOR_NUM),
	.idProduct =		cpu_to_le16(HIDG_PRODUCT_NUM),
	.bcdDevice = 0x0300,
	.iManufacturer = 1,
	.iProduct = 2,
	.iSerialNumber = 3,

	.bNumConfigurations =	1,
};

//static const struct usb_descriptor_header *otg_desc[2];

static struct usb_otg_descriptor otg_descriptor = {
	.bLength =		sizeof otg_descriptor,
	.bDescriptorType =	USB_DT_OTG,

	/* REVISIT SRP-only hardware is possible, although
	 * it would not be called "OTG" ...
	 */
	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
};

static const struct usb_descriptor_header *otg_desc[] = {
	(struct usb_descriptor_header *) &otg_descriptor,
	NULL,
};

/* string IDs are assigned dynamically */
static struct usb_string strings_dev[] = {
	[USB_GADGET_MANUFACTURER_IDX].s = "",
	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
	[USB_GADGET_SERIAL_IDX].s = "",
	{  } /* end of list */
};

static struct usb_gadget_strings stringtab_dev = {
	.language	= 0x0409,	/* en-us */
	.strings	= strings_dev,
};

static struct usb_gadget_strings *dev_strings[] = {
	&stringtab_dev,
	NULL,
};



/****************************** Configurations ******************************/

static int do_config(struct usb_configuration *c)
{
	struct hidg_func_node *e, *n;
	int status = 0;

	printk(" \n do config \n");

	if (gadget_is_otg(c->cdev->gadget)) {
		c->descriptors = otg_desc;
		c->bmAttributes |= USB_CONFIG_ATT_SELFPOWER;

		printk(" \n config as otg \n");
	}

	list_for_each_entry(e, &hidg_func_list, node) {
		e->f = usb_get_function(e->fi);
		if (IS_ERR(e->f))
			goto put;
		status = usb_add_function(c, e->f);
		if (status < 0) {
			usb_put_function(e->f);
			goto put;
		}
	}

	return 0;
put:
	list_for_each_entry(n, &hidg_func_list, node) {
		if (n == e)
			break;
		usb_remove_function(c, n->f);
		usb_put_function(n->f);
	}
	return status;
}

static struct usb_configuration config_driver = {
	.label			= "encore HID Gadget",
	.bConfigurationValue	= 1,
	/* .iConfiguration = DYNAMIC */
	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
};

/****************************** Gadget Bind ******************************/

static int hid_bind(struct usb_composite_dev *cdev)
{
	struct usb_gadget *gadget = cdev->gadget;
	struct list_head *tmp;
	struct hidg_func_node *n, *m;
	struct f_hid_opts *hid_opts;
	int status, funcs = 0;

	list_for_each(tmp, &hidg_func_list)
		funcs++;

	if (!funcs)
		return -ENODEV;

	list_for_each_entry(n, &hidg_func_list, node) {
		n->fi = usb_get_function_instance("hid");
		if (IS_ERR(n->fi)) {
			status = PTR_ERR(n->fi);
			goto put;
		}
		hid_opts = container_of(n->fi, struct f_hid_opts, func_inst);
		hid_opts->subclass = n->func->subclass;
		hid_opts->protocol = n->func->protocol;
		hid_opts->report_length = n->func->report_length;
		hid_opts->report_desc_length = n->func->report_desc_length;
		hid_opts->report_desc = n->func->report_desc;
	}


	/* Allocate string descriptor numbers ... note that string
	 * contents can be overridden by the composite_dev glue.
	 */

	status = usb_string_ids_tab(cdev, strings_dev);
	if (status < 0)
		goto put;
	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;

	if (gadget_is_otg(gadget) && !otg_desc[0]) {
		struct usb_descriptor_header *usb_desc;

		usb_desc = usb_otg_descriptor_alloc(gadget);
		if (!usb_desc)
			goto put;
		usb_otg_descriptor_init(gadget, usb_desc);
		otg_desc[0] = usb_desc;
		otg_desc[1] = NULL;
	}

	/* register our configuration */
	status = usb_add_config(cdev, &config_driver, do_config);
	if (status < 0)
		goto free_otg_desc;

	usb_composite_overwrite_options(cdev, &coverwrite);
	dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");

	return 0;

free_otg_desc:
	kfree(otg_desc[0]);
	otg_desc[0] = NULL;
put:
	list_for_each_entry(m, &hidg_func_list, node) {
		if (m == n)
			break;
		usb_put_function_instance(m->fi);
	}
	return status;
}

static int hid_unbind(struct usb_composite_dev *cdev)
{

#if 1
	struct hidg_func_node *n;

	list_for_each_entry(n, &hidg_func_list, node) {
		usb_put_function(n->f);
		usb_put_function_instance(n->fi);
	}

	kfree(otg_desc[0]);
	otg_desc[0] = NULL;

	printk("hid unbind \n \n");
	return 0;
#endif
}

static int hidg_plat_driver_probe(struct platform_device *pdev)
{
	struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev);
	struct hidg_func_node *entry;

	if (!func) {
		dev_err(&pdev->dev, "Platform data missing\n");
		return -ENODEV;
	}

#if 1
	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
	if (!entry)
		return -ENOMEM;

	entry->func = func;
	list_add_tail(&entry->node, &hidg_func_list);

#endif
	
	return 0;
}

static int hidg_plat_driver_remove(struct platform_device *pdev)
{
	struct hidg_func_node *e, *n;
#if 1
	list_for_each_entry_safe(e, n, &hidg_func_list, node) {
		list_del(&e->node);
		kfree(e);
	}
#endif
	printk("highg driver remove \n \n");
	return 0;
}


/****************************** Some noise ******************************/


static struct usb_composite_driver hidg_driver = {
	.name		= "g_hid",
	.dev		= &device_desc,
	.strings	= dev_strings,
	.max_speed	= USB_SPEED_HIGH,
	.bind		= hid_bind,
	.unbind		= __exit_p(hid_unbind),
};

static struct platform_driver hidg_plat_driver = {
	.remove		= hidg_plat_driver_remove,
	.driver		= {
		.owner = THIS_MODULE,
		.name	= "hidg",
	},
};


/* This is a quick and dirty hack to demonstrate the gadget hid driver.
   Normally the platform_device descriptor would be part of the board
   support for the device, e.g. in arch/arm/mach-omap2/devices.c,
   but for convenience I am putting it in to the g_hid module to make
   easier for testing.
   The structures my_hid_data and my_hid are straight from 
   Documentation/usb/gadget_hid. txt   
 */

/* hid descriptor for a keyboard */
#if 1 
static struct hidg_func_descriptor my_hid_data = {
        .subclass               = 0, 
        .protocol               = 0, 
        .report_length          = 8,
        .report_desc_length     = 115,
        .report_desc            = {
					0x06, 0xFF, 0x00,      /* USAGE_PAGE (Vendor Page: 0xFF00) */                       
					0x09, 0x01,            /* USAGE (Demo Kit)               */    
					0xa1, 0x01,            /* COLLECTION (Application)       */            
					/* 6 */

					/* REPORT_ID 1 		*/        //For Graphite
					0x85, 0x01,  		/*     REPORT_ID (1)		     */
					0x09, 0x01,            /*    USAGE (Graphite Command)	   */
					0x15, 0x00,            /*    LOGICAL_MINIMUM (0)         */          
					0x26, 0xff, 0x00,      /*     LOGICAL_MAXIMUM (255)  */           
					0x75, 0x08,            /*     REPORT_SIZE (8)            */        
					0x95, 0x3f,            /*     REPORT_COUNT (254)          */       
					0xB1, 0x82,            /*    FEATURE (Data,Var,Abs,Vol) */     

					0x85, 0x01,            /*     REPORT_ID (1)              */
					0x09, 0x01,            /*     USAGE (Command)              */
					0x91, 0x82,            /*     OUTPUT (Data,Var,Abs,Vol)  */
					/* 26 */

					/* REPORT_ID 2 */					//From Host Command 					
					0x85, 0x02,		/*     REPORT_ID 2		     */
					0x09, 0x02,		/*     USAGE (Command)	             */
					0x15, 0x00,            /*     LOGICAL_MINIMUM (0)          */          
					0x26, 0xff, 0x00,      /*     LOGICAL_MAXIMUM (255)        */           
					0x75, 0x08,            /*     REPORT_SIZE (8)            */        
					0x95, 0x3f, 						/*     REPORT_COUNT (254)          */       
					0xB1, 0x82,             /*    FEATURE (Data,Var,Abs,Vol) */     

					0x85, 0x02,  					 /*     REPORT_ID (2)              */
					0x09, 0x02,            /*     USAGE (Command)              */
					0x91, 0x82,            /*     OUTPUT (Data,Var,Abs,Vol)  */
					/* 46 */
					//------------------------------------------------------------------	
					/* REPORT_ID 3 */ 

					0x85, 0x03, 					 /*     REPORT_ID 3		             */
					0x09, 0x03,            /*     USAGE (Command)	           */
					0x15, 0x00,            /*     LOGICAL_MINIMUM (0)        */          
					0x26, 0xff, 0x00,      /*     LOGICAL_MAXIMUM (255)        */           
					0x75, 0x08,            /*     REPORT_SIZE (8)            */        
					0x96, 0xff,0x07,       /*     REPORT_COUNT (2047)        */       
					0xB1, 0x82,             /*    FEATURE (Data,Var,Abs,Vol) */     

					0x85, 0x03,  						/*     REPORT_ID (3)              */
					0x09, 0x03,            /*     USAGE (Command)              */
					0x91, 0x82,            /*     OUTPUT (Data,Var,Abs,Vol)  */	
					//----------------------------------------------------------------- 
					/* REPORT_ID 7 */ 
					0x85, 0x07,            //     REPORT_ID (7)                     
					0x09, 0x07,            //     USAGE (command)                       
					0x15, 0x00,            //     LOGICAL_MINIMUM (0)                       
					0x26, 0xff, 0x00,      //     LOGICAL_MAXIMUM (255)                       
					0x75, 0x08,            //     REPORT_SIZE (8)  			  	  	  
					0x95, 0x3e,    				//     REPORT_COUNT (62)  		/* Set report size */   
					0xB1, 0x82,            //     FEATURE (Data,Var,Abs,Vol)                 

					0x85, 0x07,            //     REPORT_ID (7)                               
					0x09, 0x07,            //     USAGE (Command)                                  
					0x81, 0x82,            //     INPUT (Data,Var,Abs,Vol)   

					/* REPORT_ID 8 */ 
					0x85, 0x08,            /*     REPORT_ID 8		     */
					0x09, 0x08,            /*     USAGE (Commnad)	           */
					0x15, 0x00,            /*     LOGICAL_MINIMUM (0)        */          
					0x26, 0xff, 0x00,      /*     LOGICAL_MAXIMUM (255)      */           
					0x75, 0x08,            /*     REPORT_SIZE (8)            */        
					0x96, 0xff,0x03,       /*     REPORT_COUNT (1023)        */       
					0xB1, 0x82,            /*    FEATURE (Data,Var,Abs,Vol)  */     

					0x85, 0x08,            /*     REPORT_ID (8)              */
					0x09, 0x08,            /*     USAGE (Command)            */
					0x81, 0x82,            /*     INPUT (Data,Var,Abs,Vol)   */

					0xc0 	                 /*     END_COLLECTION	             */
         			}
};
#endif

#if 0
/* hid descriptor for a keyboard */
	static struct hidg_func_descriptor my_hid_data = {
		.subclass		= 0, /* No subclass */
		.protocol		= 1, /* Keyboard */
		.report_length		= 8,
		.report_desc_length	= 63,
		.report_desc		= {
			0x05, 0x01,	/* USAGE_PAGE (Generic Desktop)	          */
			0x09, 0x06,	/* USAGE (Keyboard)                       */
			0xa1, 0x01,	/* COLLECTION (Application)               */
			0x05, 0x07,	/*   USAGE_PAGE (Keyboard)                */
			0x19, 0xe0,	/*   USAGE_MINIMUM (Keyboard LeftControl) */
			0x29, 0xe7,	/*   USAGE_MAXIMUM (Keyboard Right GUI)   */
			0x15, 0x00,	/*   LOGICAL_MINIMUM (0)                  */
			0x25, 0x01,	/*   LOGICAL_MAXIMUM (1)                  */
			0x75, 0x01,	/*   REPORT_SIZE (1)                      */
			0x95, 0x08,	/*   REPORT_COUNT (8)                     */
			0x81, 0x02,	/*   INPUT (Data,Var,Abs)                 */
			0x95, 0x01,	/*   REPORT_COUNT (1)                     */
			0x75, 0x08,	/*   REPORT_SIZE (8)                      */
			0x81, 0x03,	/*   INPUT (Cnst,Var,Abs)                 */
			0x95, 0x05,	/*   REPORT_COUNT (5)                     */
			0x75, 0x01,	/*   REPORT_SIZE (1)                      */
			0x05, 0x08,	/*   USAGE_PAGE (LEDs)                    */
			0x19, 0x01,	/*   USAGE_MINIMUM (Num Lock)             */
			0x29, 0x05,	/*   USAGE_MAXIMUM (Kana)                 */
			0x91, 0x02,	/*   OUTPUT (Data,Var,Abs)                */
			0x95, 0x01,	/*   REPORT_COUNT (1)                     */
			0x75, 0x03,	/*   REPORT_SIZE (3)                      */
			0x91, 0x03,	/*   OUTPUT (Cnst,Var,Abs)                */
			0x95, 0x06,	/*   REPORT_COUNT (6)                     */
			0x75, 0x08,	/*   REPORT_SIZE (8)                      */
			0x15, 0x00,	/*   LOGICAL_MINIMUM (0)                  */
			0x25, 0x65,	/*   LOGICAL_MAXIMUM (101)                */
			0x05, 0x07,	/*   USAGE_PAGE (Keyboard)                */
			0x19, 0x00,	/*   USAGE_MINIMUM (Reserved)             */
			0x29, 0x65,	/*   USAGE_MAXIMUM (Keyboard Application) */
			0x81, 0x00,	/*   INPUT (Data,Ary,Abs)                 */
			0xc0		/* END_COLLECTION                         */
		}
	};
#endif
static struct platform_device my_hid = {
        .name                   = "hidg",
        .id                     = 0,
        .num_resources          = 0,
        .resource               = 0,
        .dev.platform_data      = &my_hid_data,
};
/* End hack */

MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard");
MODULE_LICENSE("GPL");

static int __init hidg_init(void)
{
	int status;

	status = platform_device_register(&my_hid);
	if (status < 0)
	{
		printk("gHID:1 \n \n");
		//platform_driver_unregister(&my_hid);
		return status;
	}

	status = platform_driver_probe(&hidg_plat_driver,hidg_plat_driver_probe);
	if (status < 0)
	{
		printk("Driver probe unsucess \n \n ");
		return status;
	}
	status = usb_composite_probe(&hidg_driver);
	if (status < 0)
	{
		printk("usb composite unsucess \n \n");
		platform_driver_unregister(&hidg_plat_driver);
		platform_device_unregister(&my_hid);
	}
	return status;
}
module_init(hidg_init);

static void __exit hidg_cleanup(void)
{
	printk("exit hidg \n \n");
	platform_driver_unregister(&hidg_plat_driver);
	usb_composite_unregister(&hidg_driver);
	platform_driver_unregister(&my_hid);
	hidg_plat_driver_remove(&my_hid);
}
module_exit(hidg_cleanup);

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux