RE: [PATCH 3/5] usb: gadget/uvc: Add super-speed support to UVC webcam gadget
Hi Laurent, -Original Message- From: Laurent Pinchart [mailto:laurent.pinch...@ideasonboard.com] Sent: Monday, June 11, 2012 12:55 PM To: Bhupesh SHARMA Cc: linux-...@vger.kernel.org; ba...@ti.com; linux- me...@vger.kernel.org Subject: Re: [PATCH 3/5] usb: gadget/uvc: Add super-speed support to UVC webcam gadget Hi Bhupesh, (Dropping Greg from the CC list, I think he gets enough e-mails already without our help :-)) Ofcourse :) On Saturday 09 June 2012 13:39:34 Bhupesh SHARMA wrote: Hi Laurent, Thanks for your review comments. Please find my comments inline: As Felipe has already applied the patch to his public tree, I'll send incremental cleanup patches. Here's my review nonetheless, with a question which I'd like to know your opinion about to write the cleanup patches. Not to worry, I can send incremental patches. I've already prepared incremental patches so I'll send them. Ok. Anyways I need to ensure 4/5 and 5/5 patches of the series also cleanly apply on Felipe's tree as he was facing issues while applying these patches. Please review 4/5 and 5/5 patches of this patch-set as well and then I can re-circulate patches for re-review and incorporation in gadget-next. I will review 4/5 and 5/5 and ask you to post a new version. I'll send incremental patches for 1/5 to 3/5 myself. Sure. On Friday 01 June 2012 15:08:56 Bhupesh Sharma wrote: This patch adds super-speed support to UVC webcam gadget. Also in this patch: - We add the configurability to pass bInterval, bMaxBurst, mult factors for video streaming endpoint (ISOC IN) through module parameters. - We use config_ep_by_speed helper routine to configure video streaming endpoint. Signed-off-by: Bhupesh Sharma bhupesh.sha...@st.com [snip] +static unsigned streaming_interval = 1; +module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_interval, 1 - 16); + +static unsigned streaming_maxpacket = 1024; unsigned int please. Ok. +module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxpacket, 0 - 1023 (fs), 0 - 1024 (hs/ss)); + +static unsigned streaming_mult; +module_param(streaming_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_mult, 0 - 2 (hs/ss only)); I'd rather like to integrate this into the streaming_maxpacket parameter, and compute the multiplier at runtime. This shouldn't be difficult for high speed, the multiplier for max packet sizes between 1 and 1024 is 1, between 1025 and 2048 is 2 and between 2049 and 3072 is 3. There is a specific purpose for keeping these three module parameters separate, with xHCI hosts and USB3 device-side controllers still in stabilization phase, it is easy for a person switching from USB2.0 to USB3.0 to understand these module parameters as the major difference points in respect to ISOC IN endpoints. A similar methodology is already used in the reference USB gadget zero (see here [1]) and I have tried to keep the same methodology here as well. [1] http://git.kernel.org/?p=linux/kernel/git/balbi/usb.git;a=blob;f=driver s/us b/gadget/f_sourcesink.c Having another driver implementing the same doesn't automatically make it right ;-) I still think the maxpacket and mult values should be combined into a single parameter. There's a single way to split a given number of bytes into maxpacket and mult values. Felipe (and others), any opinion on this ? Ok. I will ask Felipe and others to pitch in as well before we finalize our approach. +static unsigned streaming_maxburst; +module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxburst, 0 - 15 (ss only)); Do you think maxburst could also be integrated into the streaming_maxpacket parameter ? Put it another way, can we computer the multiplier and the burst value from a single maximum number of bytes per service interval, or do they have to be specified independently ? If using more than one burst, the wMaxPacketSize value must be 1024 for HS. Only multiples of 1024 higher than 1024 can thus be achieved through different multipler/burst settings. Pls see above.. I'll keep this parameter separate. When maxburst is non-zero the maxpacket value must be a multiple of 1024. If the user-specified value is incorrect the driver should error out. I forgot to mention that S_IWUSR looks unsafe to me. If we allow changing the mackpacket, mult and maxburst values at runtime, the function could be bound after one of the values have been changed but not the others. [snip] + +/* super speed support */ +static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE
Re: [PATCH 3/5] usb: gadget/uvc: Add super-speed support to UVC webcam gadget
Hi Bhupesh, (Dropping Greg from the CC list, I think he gets enough e-mails already without our help :-)) On Saturday 09 June 2012 13:39:34 Bhupesh SHARMA wrote: Hi Laurent, Thanks for your review comments. Please find my comments inline: As Felipe has already applied the patch to his public tree, I'll send incremental cleanup patches. Here's my review nonetheless, with a question which I'd like to know your opinion about to write the cleanup patches. Not to worry, I can send incremental patches. I've already prepared incremental patches so I'll send them. Anyways I need to ensure 4/5 and 5/5 patches of the series also cleanly apply on Felipe's tree as he was facing issues while applying these patches. Please review 4/5 and 5/5 patches of this patch-set as well and then I can re-circulate patches for re-review and incorporation in gadget-next. I will review 4/5 and 5/5 and ask you to post a new version. I'll send incremental patches for 1/5 to 3/5 myself. On Friday 01 June 2012 15:08:56 Bhupesh Sharma wrote: This patch adds super-speed support to UVC webcam gadget. Also in this patch: - We add the configurability to pass bInterval, bMaxBurst, mult factors for video streaming endpoint (ISOC IN) through module parameters. - We use config_ep_by_speed helper routine to configure video streaming endpoint. Signed-off-by: Bhupesh Sharma bhupesh.sha...@st.com [snip] +static unsigned streaming_interval = 1; +module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_interval, 1 - 16); + +static unsigned streaming_maxpacket = 1024; unsigned int please. Ok. +module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxpacket, 0 - 1023 (fs), 0 - 1024 (hs/ss)); + +static unsigned streaming_mult; +module_param(streaming_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_mult, 0 - 2 (hs/ss only)); I'd rather like to integrate this into the streaming_maxpacket parameter, and compute the multiplier at runtime. This shouldn't be difficult for high speed, the multiplier for max packet sizes between 1 and 1024 is 1, between 1025 and 2048 is 2 and between 2049 and 3072 is 3. There is a specific purpose for keeping these three module parameters separate, with xHCI hosts and USB3 device-side controllers still in stabilization phase, it is easy for a person switching from USB2.0 to USB3.0 to understand these module parameters as the major difference points in respect to ISOC IN endpoints. A similar methodology is already used in the reference USB gadget zero (see here [1]) and I have tried to keep the same methodology here as well. [1] http://git.kernel.org/?p=linux/kernel/git/balbi/usb.git;a=blob;f=drivers/us b/gadget/f_sourcesink.c Having another driver implementing the same doesn't automatically make it right ;-) I still think the maxpacket and mult values should be combined into a single parameter. There's a single way to split a given number of bytes into maxpacket and mult values. Felipe (and others), any opinion on this ? +static unsigned streaming_maxburst; +module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxburst, 0 - 15 (ss only)); Do you think maxburst could also be integrated into the streaming_maxpacket parameter ? Put it another way, can we computer the multiplier and the burst value from a single maximum number of bytes per service interval, or do they have to be specified independently ? If using more than one burst, the wMaxPacketSize value must be 1024 for HS. Only multiples of 1024 higher than 1024 can thus be achieved through different multipler/burst settings. Pls see above.. I'll keep this parameter separate. When maxburst is non-zero the maxpacket value must be a multiple of 1024. If the user-specified value is incorrect the driver should error out. I forgot to mention that S_IWUSR looks unsafe to me. If we allow changing the mackpacket, mult and maxburst values at runtime, the function could be bound after one of the values have been changed but not the others. [snip] + +/* super speed support */ +static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), + .bInterval =8, +}; The FS/HS/SS control endpoint descriptors are identical, there's no need to define separate descriptors. You also don't set the SS endpoint number to the FS endpoint number. As you don't call usb_ep_autoconfig() on the SS endpoint, I doubt this will work in SS. Have you tested SS support ? Yes. I have tested
Re: [PATCH 3/5] usb: gadget/uvc: Add super-speed support to UVC webcam gadget
Hi Bhupesh, Thanks for the patch. As Felipe has already applied the patch to his public tree, I'll send incremental cleanup patches. Here's my review nonetheless, with a question which I'd like to know your opinion about to write the cleanup patches. On Friday 01 June 2012 15:08:56 Bhupesh Sharma wrote: This patch adds super-speed support to UVC webcam gadget. Also in this patch: - We add the configurability to pass bInterval, bMaxBurst, mult factors for video streaming endpoint (ISOC IN) through module parameters. - We use config_ep_by_speed helper routine to configure video streaming endpoint. Signed-off-by: Bhupesh Sharma bhupesh.sha...@st.com --- drivers/usb/gadget/f_uvc.c | 241 +++- drivers/usb/gadget/f_uvc.h |8 +- drivers/usb/gadget/uvc.h|4 +- drivers/usb/gadget/webcam.c | 29 +- 4 files changed, 247 insertions(+), 35 deletions(-) diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index dd7d7a9..2a8bf06 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -29,6 +29,25 @@ unsigned int uvc_gadget_trace_param; +/*- */ + +/* module parameters specific to the Video streaming endpoint */ +static unsigned streaming_interval = 1; +module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_interval, 1 - 16); + +static unsigned streaming_maxpacket = 1024; unsigned int please. +module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxpacket, 0 - 1023 (fs), 0 - 1024 (hs/ss)); + +static unsigned streaming_mult; +module_param(streaming_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_mult, 0 - 2 (hs/ss only)); I'd rather like to integrate this into the streaming_maxpacket parameter, and compute the multiplier at runtime. This shouldn't be difficult for high speed, the multiplier for max packet sizes between 1 and 1024 is 1, between 1025 and 2048 is 2 and between 2049 and 3072 is 3. +static unsigned streaming_maxburst; +module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxburst, 0 - 15 (ss only)); Do you think maxburst could also be integrated into the streaming_maxpacket parameter ? Put it another way, can we computer the multiplier and the burst value from a single maximum number of bytes per service interval, or do they have to be specified independently ? If using more than one burst, the wMaxPacketSize value must be 1024 for HS. Only multiples of 1024 higher than 1024 can thus be achieved through different multipler/burst settings. + /* -- * Function descriptors */ @@ -84,7 +103,7 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = { .iInterface= 0, }; -static struct usb_endpoint_descriptor uvc_control_ep __initdata = { +static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = { .bLength= USB_DT_ENDPOINT_SIZE, .bDescriptorType= USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -124,7 +143,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { .iInterface= 0, }; -static struct usb_endpoint_descriptor uvc_streaming_ep = { +static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { .bLength= USB_DT_ENDPOINT_SIZE, .bDescriptorType= USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -133,15 +152,72 @@ static struct usb_endpoint_descriptor uvc_streaming_ep = { .bInterval= 1, }; +static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { + .bLength= USB_DT_ENDPOINT_SIZE, + .bDescriptorType= USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 1, wMaxPacketSize and bInterval are now initialized from module parameters, so I'd leave it to zero and add a comment about it. +}; Please keep the indentation style consistent with the rest of the file. + +/* super speed support */ +static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), + .bInterval =8, +}; The FS/HS/SS control endpoint descriptors are identical, there's no need to define separate descriptors. You also don't set the SS endpoint number to the FS endpoint number. As you don't call
RE: [PATCH 3/5] usb: gadget/uvc: Add super-speed support to UVC webcam gadget
Hi Laurent, Thanks for your review comments. Please find my comments inline: As Felipe has already applied the patch to his public tree, I'll send incremental cleanup patches. Here's my review nonetheless, with a question which I'd like to know your opinion about to write the cleanup patches. Not to worry, I can send incremental patches. Anyways I need to ensure 4/5 and 5/5 patches of the series also cleanly apply on Felipe's tree as he was facing issues while applying these patches. Please review 4/5 and 5/5 patches of this patch-set as well and then I can re-circulate patches for re-review and incorporation in gadget-next. On Friday 01 June 2012 15:08:56 Bhupesh Sharma wrote: This patch adds super-speed support to UVC webcam gadget. Also in this patch: - We add the configurability to pass bInterval, bMaxBurst, mult factors for video streaming endpoint (ISOC IN) through module parameters. - We use config_ep_by_speed helper routine to configure video streaming endpoint. Signed-off-by: Bhupesh Sharma bhupesh.sha...@st.com --- drivers/usb/gadget/f_uvc.c | 241 +++- drivers/usb/gadget/f_uvc.h |8 +- drivers/usb/gadget/uvc.h|4 +- drivers/usb/gadget/webcam.c | 29 +- 4 files changed, 247 insertions(+), 35 deletions(-) diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index dd7d7a9..2a8bf06 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -29,6 +29,25 @@ unsigned int uvc_gadget_trace_param; +/*-- --- */ + +/* module parameters specific to the Video streaming endpoint */ +static unsigned streaming_interval = 1; +module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_interval, 1 - 16); + +static unsigned streaming_maxpacket = 1024; unsigned int please. Ok. +module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxpacket, 0 - 1023 (fs), 0 - 1024 (hs/ss)); + +static unsigned streaming_mult; +module_param(streaming_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_mult, 0 - 2 (hs/ss only)); I'd rather like to integrate this into the streaming_maxpacket parameter, and compute the multiplier at runtime. This shouldn't be difficult for high speed, the multiplier for max packet sizes between 1 and 1024 is 1, between 1025 and 2048 is 2 and between 2049 and 3072 is 3. There is a specific purpose for keeping these three module parameters separate, with xHCI hosts and USB3 device-side controllers still in stabilization phase, it is easy for a person switching from USB2.0 to USB3.0 to understand these module parameters as the major difference points in respect to ISOC IN endpoints. A similar methodology is already used in the reference USB gadget zero (see here [1]) and I have tried to keep the same methodology here as well. [1] http://git.kernel.org/?p=linux/kernel/git/balbi/usb.git;a=blob;f=drivers/usb/gadget/f_sourcesink.c +static unsigned streaming_maxburst; +module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxburst, 0 - 15 (ss only)); Do you think maxburst could also be integrated into the streaming_maxpacket parameter ? Put it another way, can we computer the multiplier and the burst value from a single maximum number of bytes per service interval, or do they have to be specified independently ? If using more than one burst, the wMaxPacketSize value must be 1024 for HS. Only multiples of 1024 higher than 1024 can thus be achieved through different multipler/burst settings. Pls see above.. + /* - - * Function descriptors */ @@ -84,7 +103,7 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = { .iInterface = 0, }; -static struct usb_endpoint_descriptor uvc_control_ep __initdata = { +static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = { .bLength= USB_DT_ENDPOINT_SIZE, .bDescriptorType= USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -124,7 +143,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { .iInterface = 0, }; -static struct usb_endpoint_descriptor uvc_streaming_ep = { +static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { .bLength= USB_DT_ENDPOINT_SIZE, .bDescriptorType= USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -133,15 +152,72 @@ static struct usb_endpoint_descriptor uvc_streaming_ep = { .bInterval = 1, }; +static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { + .bLength= USB_DT_ENDPOINT_SIZE, + .bDescriptorType
[PATCH 3/5] usb: gadget/uvc: Add super-speed support to UVC webcam gadget
This patch adds super-speed support to UVC webcam gadget. Also in this patch: - We add the configurability to pass bInterval, bMaxBurst, mult factors for video streaming endpoint (ISOC IN) through module parameters. - We use config_ep_by_speed helper routine to configure video streaming endpoint. Signed-off-by: Bhupesh Sharma bhupesh.sha...@st.com --- drivers/usb/gadget/f_uvc.c | 241 ++- drivers/usb/gadget/f_uvc.h |8 +- drivers/usb/gadget/uvc.h|4 +- drivers/usb/gadget/webcam.c | 29 +- 4 files changed, 247 insertions(+), 35 deletions(-) diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index dd7d7a9..2a8bf06 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -29,6 +29,25 @@ unsigned int uvc_gadget_trace_param; +/*-*/ + +/* module parameters specific to the Video streaming endpoint */ +static unsigned streaming_interval = 1; +module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_interval, 1 - 16); + +static unsigned streaming_maxpacket = 1024; +module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxpacket, 0 - 1023 (fs), 0 - 1024 (hs/ss)); + +static unsigned streaming_mult; +module_param(streaming_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_mult, 0 - 2 (hs/ss only)); + +static unsigned streaming_maxburst; +module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(streaming_maxburst, 0 - 15 (ss only)); + /* -- * Function descriptors */ @@ -84,7 +103,7 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = { .iInterface = 0, }; -static struct usb_endpoint_descriptor uvc_control_ep __initdata = { +static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = { .bLength= USB_DT_ENDPOINT_SIZE, .bDescriptorType= USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -124,7 +143,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { .iInterface = 0, }; -static struct usb_endpoint_descriptor uvc_streaming_ep = { +static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { .bLength= USB_DT_ENDPOINT_SIZE, .bDescriptorType= USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, @@ -133,15 +152,72 @@ static struct usb_endpoint_descriptor uvc_streaming_ep = { .bInterval = 1, }; +static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { + .bLength= USB_DT_ENDPOINT_SIZE, + .bDescriptorType= USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 1, +}; + +/* super speed support */ +static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), + .bInterval =8, +}; + +static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = { + .bLength = sizeof uvc_ss_control_comp, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ + .wBytesPerInterval =cpu_to_le16(STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval =4, +}; + +static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { + .bLength = sizeof uvc_ss_streaming_comp, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + .bMaxBurst =0, + .bmAttributes = 0, + .wBytesPerInterval =cpu_to_le16(1024), +}; + static const struct usb_descriptor_header * const uvc_fs_streaming[] = { (struct usb_descriptor_header *) uvc_streaming_intf_alt1, - (struct usb_descriptor_header *) uvc_streaming_ep, + (struct usb_descriptor_header *) uvc_fs_streaming_ep, NULL, }; static const struct usb_descriptor_header * const